home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual Foxpro 6.0 (Ent. Edition) / Vf6ent Extractor.EXE / GENMENU.PRG < prev    next >
Encoding:
Text File  |  1998-05-26  |  74.2 KB  |  2,537 lines

  1. ******************************************************************************
  2. * GENMENU - Menu code generator.
  3. *
  4. * Copyright (c) 1990 - 1995 Microsoft Corp.
  5. * 1 Microsoft Way
  6. * Redmond, WA 98052
  7. *
  8. * Description:
  9. * This program generates menu code which was designed in the
  10. * FoxPro 3.0 MENU BUILDER.
  11. *
  12. * Modification History:
  13. * December 13, 1990        JAC        Program Created
  14. *
  15. * Modified for FoxPro 2.5 by WJK
  16. * Modified for FoxPro 3.0 by DTA
  17. * Modified for FoxPro 5.0 by RB
  18. *
  19. ******************************************************************************
  20. * MS SourceSafe Keywords:
  21. * $Workfile: GENMENU.PRG $
  22. *   $Author: Dta $
  23. *     $Date: 3/19/95 1:04a $
  24. *  $Logfile: /Genmenu/GENMENU.PRG $
  25. *  $Modtime: 3/19/95 1:04a $
  26. * $Revision: 8 $
  27. *
  28. * NOTE: Revisions history kept at end of file.
  29. ******************************************************************************
  30. ******************************************************************************
  31. *
  32. * Declare Constants
  33. *
  34. ******************************************************************************
  35. * Move constants above executable code [Rev: 3][BEG]
  36. #DEFINE c_DEBUG .F.  && Add debug mode [Rev: 4][ADD]
  37. *
  38. #DEFINE c_esc    CHR(27)
  39. #DEFINE c_null    CHR(0)
  40. #DEFINE c_CRLF  CHR(13) + CHR(10)   && Carriage return + Line feed constant [Rev: 6][ADD]
  41. #DEFINE c_aliaslen 255               && Support long file names [Rev: 7][MOD]
  42. *
  43. * Possible values of Objtype field in SCX database.
  44. *
  45. #DEFINE c_menu        1
  46. #DEFINE c_submenu    2
  47. #DEFINE c_item        3
  48. #DEFINE c_shortcut    4
  49. #DEFINE c_sdimenu    5
  50. *
  51. * Some of the values of Objcode field in SCX database.
  52. *
  53. #DEFINE    c_global         1
  54. #DEFINE c_proc          80
  55. #DEFINE c_maxsnippets   25
  56. #DEFINE c_maxpads        25
  57. #DEFINE c_pjx20flds        33
  58. #DEFINE c_pjxflds        28   && Changed from 31 [Rev: 2][MOD]
  59. #DEFINE c_mnxflds        23
  60. #DEFINE c_20mnxflds        22
  61. #DEFINE c_space         40   && Used by Thermfname 
  62. *
  63. * Developer Information
  64. *
  65. #DEFINE c_authorlen        45
  66. #DEFINE c_complen        45
  67. #DEFINE c_addrlen        45
  68. #DEFINE c_citylen        20
  69. #DEFINE c_statlen        5
  70. #DEFINE c_ziplen        10
  71. #DEFINE c_countrylen    40
  72. *
  73. * Menu / pad location
  74. *
  75. #DEFINE c_replace        0
  76. #DEFINE c_append        1
  77. #DEFINE c_before        2
  78. #DEFINE c_after            3
  79. *
  80. #DEFINE c_pathsep  "\"
  81. *
  82. * Add support for negotiate [Rev: 2][BEG]
  83. #DEFINE c_neg_flag      "LOCATION"
  84. #DEFINE c_neg_none            0
  85. #DEFINE c_neg_left          1
  86. #DEFINE c_neg_middle        2
  87. #DEFINE c_neg_right         3
  88. * Add support for negotiate [Rev: 2][BEG]
  89. *
  90. * Add localization support [Rev: 2][BEG]
  91. #DEFINE c_hdr_author_LOC    "Author's Name"
  92. #DEFINE c_hdr_company_LOC   "Company Name"
  93. #DEFINE c_hdr_address_LOC   "Address"
  94. #DEFINE c_hdr_city_LOC      "City"
  95. #DEFINE c_hdr_state_LOC     "  "
  96. #DEFINE c_hdr_zip_LOC       "Zip"
  97. #DEFINE c_hdr_ctry_LOC      "Country"
  98. #DEFINE c_hdr_copyright_LOC Copyright (C)
  99. #DEFINE c_hdr_descript_LOC  Description:
  100. #DEFINE c_hdr_string_LOC    This PROGRAM was automatically generated BY GENMENU.
  101. #DEFINE c_shortcutdef_LOC  "FoxShortcutMenu"
  102.  
  103. *
  104. #DEFINE c_snip_setup_LOC    " Setup Code"
  105. #DEFINE c_snip_cleanup_LOC  " Cleanup Code & Procedures"
  106. #DEFINE c_snip_init_LOC     " Initializing Code"
  107. #DEFINE c_snip_menu_LOC     " Menu Definition"
  108.  
  109. #DEFINE c_dlgface_mac_LOC       "Geneva"
  110. #DEFINE c_dlgface_nonmac_LOC    "MS Sans Serif"
  111. #DEFINE c_dlgstyle_mac_LOC       ""
  112. #DEFINE c_dlgstyle_nonmac_LOC     ""
  113.  
  114. *
  115. * Genmenu error types
  116. *
  117. #DEFINE c_error_1        "Minor"
  118. #DEFINE c_error_2        "Serious"
  119. #DEFINE c_error_3        "Fatal"
  120. #DEFINE c_error_1Icon   64   &&   Error icons [Rev: 6][ADD]
  121. #DEFINE c_error_2Icon   48   &&   Error icons [Rev: 6][ADD]
  122. #DEFINE c_error_3Icon   16   &&   Error icons [Rev: 6][ADD]
  123. #DEFINE c_err_invnumparm_LOC     "Invalid number of parameters passed to the generator."
  124. #DEFINE c_err_badgendate_LOC     "Generator out of date."
  125. #DEFINE c_err_badrechead_LOC     "Missing header record in "
  126. #DEFINE c_err_nocloseapp_LOC     "Unable to Close the Application File."
  127. #DEFINE c_err_badmnxpre_LOC      "Menu "
  128. #DEFINE c_err_badmnxpost_LOC     " is invalid"
  129. #DEFINE c_err_nofileopen_LOC     "Cannot open file "
  130. #DEFINE c_err_badnegoval_LOC     "Invalid negotiate value in field "
  131. #DEFINE c_err_title_LOC          "Genmenu Error"
  132. #DEFINE c_err_lineno_LOC         "Line Number: "
  133. #DEFINE c_err_presskey_LOC       "Press any key to cleanup and exit..."
  134. #DEFINE c_err_noopenerr_LOC      ".ERR could not be opened..."
  135. #DEFINE c_err_toomanymemvars_LOC "Too many memvars - GENMENU will terminate..."    && ERROR 22 [Rev: 4][ADD]
  136. #DEFINE c_err_nobangallowed_LOC  "Menu file name cannot contain the character " + [" ! "]   && ! in menu [Rev: 6][ADD]
  137. *
  138. #DEFINE c_msg_gencomplete_LOC    "Generation Complete"
  139. #DEFINE c_msg_genmenudefs_LOC    "Generating menu definitions..."
  140. #DEFINE c_msg_genpopdefs_LOC     "Generating popup definitions..."
  141. #DEFINE c_msg_genprocs_LOC       "Generating procedures..."
  142. #DEFINE c_msg_gensetup_LOC       "Generating Menu Setup Code..."
  143. #DEFINE c_msg_gencleanup_LOC     "Generating Menu Cleanup Code..."
  144. #DEFINE c_msg_genstopped_LOC     "Generation process stopped."
  145. #DEFINE c_msg_genmenucode_LOC    "Generating Menu Code..."
  146. *
  147. #DEFINE c_sdierrdisplay_loc        "[This menu can only be called from a Top-Level form. "+;
  148.                                 "Ensure that your form's ShowWindow property is set to 2. "+;
  149.                                 "Read the header section of the menu's MPR file for more details.]"
  150. *
  151. #DEFINE c_ui_whereis_LOC         WHERE is
  152. * Add localization support [Rev: 2][END]
  153. *
  154. #DEFINE c_key_padhotkey_LOC      "ALT+"   && Add support for intelligent Pad hotkeys. [Rev: 7][ADD]
  155. * Move constants above executable code [Rev: 3][END]
  156. ******************************************************************************
  157. *
  158. * Main program
  159. *
  160. ******************************************************************************
  161. PARAMETER m.projdbf, m.recno
  162. PRIVATE ALL
  163. *
  164. * Setup initial environment for GENMENU
  165. *
  166. IF SET("TALK") = "ON"
  167.    SET TALK OFF
  168.    m.talkstate = "ON"
  169. ELSE
  170.    m.talkstate = "OFF"
  171. ENDIF
  172. m.coveragefile = SET("COVERAGE")
  173. m.oldtextmerge = SET("TEXTMERGE")
  174. SET COVERAGE TO
  175. m.escape = SET("ESCAPE")
  176. IF NOT c_DEBUG   && Add debug mode [Rev: 4][ADD]
  177.    SET ESCAPE OFF
  178. ENDIF
  179. m.trbetween = SET("TRBET")
  180. IF NOT c_DEBUG   && Add debug mode [Rev: 4][ADD]
  181.    SET TRBET OFF
  182. ENDIF
  183. m.comp = SET("COMPATIBLE")
  184. SET COMPATIBLE OFF
  185. mdevice = SET("DEVICE")
  186. SET DEVICE TO SCREEN
  187. m.alternate = SET("ALTE")
  188. SET ALTERNATE OFF
  189. ******************************************************************************
  190. *
  191. * Declare Variables
  192. *
  193. ******************************************************************************
  194. STORE "" TO m.cursor, m.consol, m.bell, m.onerror, m.fields, mfieldsto, ;
  195.    m.exact, m.print, m.fixed, m.delimiters, m.mpoint, m.mcollate, m.mmacdesk, m.mcpdialog 
  196. STORE 0 TO m.deci, m.memowidth
  197. *
  198. * Fonts for thermometer bar / dialogs
  199. *
  200. * Change fonts to memvars [Rev: 4][BEG]
  201. * Translate the filename into Mac native format
  202. IF _MAC
  203.    m.g_dlgface    = c_dlgface_mac_LOC
  204.    m.g_dlgsize    = 10.000
  205.    m.g_dlgstyle    = c_dlgstyle_mac_LOC
  206.    m.g_pathsep    = ":"
  207. ELSE
  208.    m.g_dlgface    = c_dlgface_nonmac_LOC
  209.    m.g_dlgsize    = 8.000
  210.    m.g_dlgstyle    = c_dlgstyle_nonmac_LOC
  211.    m.g_pathsep    = "\"
  212. ENDIF
  213. m.g_error      = .F.
  214. m.g_errlog     = ""
  215. m.g_homedir    = ""
  216. m.g_location   = 0
  217. m.g_menucolor  = 0
  218. m.g_menumark   = ""
  219. m.g_nohandle   = .T.
  220. m.g_nsnippets  = 0
  221. m.g_outfile    = ""
  222. m.g_padloca    = ""
  223. m.g_projalias  = ""
  224. m.g_projdbf    = m.projdbf
  225. m.g_projpath   = ""
  226. m.g_status     = 0
  227. m.g_snippcnt   = 0
  228. m.g_thermwidth = 0
  229. m.g_workarea   = 0
  230. m.g_graphic    = .F.
  231. m.g_20mnx       = .F.
  232. m.g_shortcut   = .F.
  233. m.g_inform     = .F.
  234. m.g_shortcutname = ""
  235. m.g_prepopup = .F.
  236. *
  237. * Add localization support [Rev: 2][BEG]
  238. m.g_devauthor  = PADR( c_hdr_author_LOC ,45," ")
  239. m.g_devcompany = PADR( c_hdr_company_LOC ,45, " ")
  240. m.g_devaddress = PADR( c_hdr_address_LOC ,45," ")
  241. m.g_devcity    = PADR( c_hdr_city_LOC ,20," ")
  242. m.g_devstate   = c_hdr_state_LOC
  243. m.g_devzip     = PADR( c_hdr_zip_LOC ,10," ")
  244. m.g_devctry    = PADR( c_hdr_ctry_LOC ,40," ")
  245. * Add localization support [Rev: 2][END]
  246. *
  247. m.g_boxstrg = ['─','─','│','│','┌','┐','└','┘','─','─','│','│','┌','┐','└','┘']
  248. *
  249. STORE "" TO m.g_corn1, m.g_corn2, m.g_corn3, m.g_corn4, m.g_corn5, ;
  250.    m.g_corn6, m.g_verti2
  251. STORE "*" TO  m.g_horiz, m.g_verti1
  252. *
  253. *
  254. * Array Declarations
  255. *
  256. * g_mnxfile [1] - Normalized path + name
  257. * g_mnxfile [2] - Basename
  258. * g_mnxfile [3] - Opened originally?
  259. * g_mnxfile [4] - Alias
  260. *
  261. DIMENSION g_mnxfile[4]
  262. g_mnxfile[1] = ""
  263. g_mnxfile[2] = ""
  264. g_mnxfile[3] = .F.
  265. g_mnxfile[4] = ""
  266. *
  267. * g_pads - names of generated menu pads
  268. *
  269. DIMENSION g_pads(c_maxpads)
  270. *
  271. * g_snippets [*,1] - generated snippet procedure name
  272. * g_snippets [*,2] - recno()
  273. *
  274. DIMENSION g_snippets (c_maxsnippets,2)
  275. g_snippets = ""
  276.  
  277. DIMENSION g_aPops(1)
  278. g_aPops=""
  279.  
  280. IF AT("WINDOWS", UPPER(VERSION())) <> 0 OR ;
  281.       AT("MAC", UPPER(VERSION())) <> 0
  282.    m.g_graphic = .T.
  283. ELSE
  284.    m.g_graphic = .F.
  285. ENDIF
  286. *
  287. * Main program
  288. *
  289. m.onerror = ON("ERROR")
  290. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  291. *
  292. IF PARAMETERS()=2
  293.    DO setup
  294.    IF validparams()
  295.       ON ESCAPE DO eschandler
  296.       SET ESCAPE ON
  297.       DO refreshprefs
  298.       DO BUILD
  299.    ENDIF
  300.    DO cleanup
  301. ELSE
  302.    DO errorhandler WITH c_err_invnumparm_LOC, LINENO(),c_error_3  && Localization support [Rev: 2][MOD]
  303. ENDIF
  304. ON ERROR &onerror
  305. *
  306. RETURN m.g_status
  307.  
  308.  
  309. ******************************************************************************
  310. *
  311. * Setup, Cleanup, Validparams, and Refreshprefs of Main Program
  312. *
  313. ******************************************************************************
  314. *
  315. * STARTUP - Create program's environment.
  316. *
  317. * Description:
  318. * Save the user's environment so that we can set it back when
  319. * we are done, then issue various SET commands. The only state
  320. * we cannot conveniently save is SET TALK, because storing the
  321. * state involves an assignment statement, and assignments
  322. * generate unwanted output if TALK is set ON.
  323. *
  324. * Side Effects:
  325. * Creates a temporary file which is deleted in the Cleanup
  326. * procedure executed at the end of MENUGEN.
  327. *
  328. FUNCTION setup
  329. CLEAR PROGRAM
  330. CLEAR GETS
  331. m.g_workarea = SELECT()
  332. m.delimiters = SET('TEXTMERGE',1)
  333. SET TEXTMERGE DELIMITERS TO
  334. SET UDFPARMS TO VALUE
  335. m.mfieldsto = SET("FIELDS",1)
  336. m.fields = SET("FIELDS")
  337. SET FIELDS TO
  338. SET FIELDS OFF
  339. m.bell = SET("BELL")
  340. SET BELL OFF
  341. m.consol = SET("CONSOLE")
  342. SET CONSOLE OFF
  343. m.cursor = SET("CURSOR")
  344. SET CURSOR OFF
  345. m.deci = SET("DECIMALS")
  346. SET DECIMALS TO 0
  347. mdevice = SET("DEVICE")
  348. SET DEVICE TO SCREEN
  349. m.memowidth = SET("MEMOWIDTH")
  350. SET MEMOWIDTH TO 256
  351. m.exact = SET("EXACT")
  352. SET EXACT ON
  353. m.print = SET("PRINT")
  354. SET PRINT OFF
  355. m.fixed = SET("FIXED")
  356. SET FIXED ON
  357. mpoint = SET("POINT")
  358. SET POINT TO "."
  359. mcollate = SET("COLLATE")
  360. SET COLLATE TO "machine"
  361. mcpdialog = SET("CPDIALOG")
  362. SET CPDIALOG OFF
  363.  
  364. #IF "MAC" $ UPPER(VERSION(1))
  365. IF _MAC
  366.    m.mmacdesk = SET("MACDESKTOP")
  367.    SET MACDESKTOP ON
  368. ENDIF
  369. #ENDIF
  370.  
  371. *
  372. * CLEANUP - restore environment to pre-execution state.
  373. *
  374. * Description:
  375. * Close all databases opened in the course of the execution of MENUGEN.
  376. * Restore the environment to the pre-execution of MENUGEN.  Delete
  377. * the VIEW file since there is no further use for it.
  378. *
  379. * Side Effects:
  380. * Closes databases.
  381. * Deletes the temporary view file.
  382. *
  383. FUNCTION cleanup
  384. PRIVATE m.delilen, m.ldelimi, m.rdelimi
  385. IF EMPTY(m.g_projalias)
  386.    RETURN
  387. ENDIF
  388. SELECT (m.g_projalias)
  389. USE
  390. IF NOT EMPTY(g_mnxfile[3])
  391.    IF USED(g_mnxfile[4])
  392.       SELECT (g_mnxfile[4])
  393.       USE
  394.    ENDIF
  395. ENDIF
  396. SELECT (m.g_workarea)
  397. m.delilen = LEN(m.delimiters)
  398. m.ldelimi = SUBSTR(m.delimiters,1,;
  399.    IIF(MOD(m.delilen,2)=0,m.delilen/2,CEILING(m.delilen/2)))
  400. m.rdelimi = SUBSTR(m.delimiters,;
  401.    IIF(MOD(m.delilen,2)=0,m.delilen/2+1,CEILING(m.delilen/2)+1))
  402. SET TEXTMERGE DELIMITERS TO m.ldelimi, m.rdelimi
  403. IF (LEN(mfieldsto) > 2048)
  404.    SET FIELDS TO
  405. ELSE
  406.    SET FIELDS TO &mfieldsto
  407. ENDIF
  408. IF m.fields = "ON"
  409.    SET FIELDS ON
  410. ELSE
  411.    SET FIELDS OFF
  412. ENDIF
  413. IF m.bell = "ON"
  414.    SET BELL ON
  415. ENDIF
  416. IF m.cursor = "ON"
  417.    SET CURSOR ON
  418. ELSE
  419.    SET CURSOR OFF
  420. ENDIF
  421. IF m.consol = "ON"
  422.    SET CONSOLE ON
  423. ENDIF
  424. IF m.escape = "ON"
  425.    SET ESCAPE ON
  426. ELSE
  427.    SET ESCAPE OFF
  428. ENDIF
  429. IF m.print = "ON"
  430.    SET PRINT ON
  431. ENDIF
  432. IF m.exact = "OFF"
  433.    SET EXACT OFF
  434. ENDIF
  435. IF m.fixed = "OFF"
  436.    SET FIXED OFF
  437. ENDIF
  438. SET DECIMALS TO m.deci
  439. SET MEMOWIDTH TO m.memowidth
  440. SET DEVICE TO &mdevice
  441. IF m.trbetween = "ON"
  442.    SET TRBET ON
  443. ENDIF
  444. IF m.comp = "ON"
  445.    SET COMPATIBLE ON
  446. ENDIF
  447. IF m.talkstate = "ON"
  448.    SET TALK ON
  449. ENDIF
  450. SET POINT TO "&mpoint"
  451. SET COLLATE TO "&mcollate"
  452. IF m.mcpdialog = "ON"
  453.    SET CPDIALOG ON
  454. ENDIF
  455. IF m.alternate = "ON"
  456.    SET ALTERNATE ON
  457. ENDIF
  458. SET MESSAGE TO
  459. #IF "MAC" $ UPPER(VERSION(1))
  460. IF _MAC
  461.    SET MACDESKTOP &mmacdesk
  462. ENDIF
  463. #ENDIF
  464.  
  465. ON ERROR &onerror
  466. IF !EMPTY(m.coveragefile)
  467.     SET COVERAGE TO (m.coveragefile) ADDITIVE
  468. ENDIF
  469. SET TEXTMERGE TO
  470. IF m.oldtextmerge = "ON"
  471.     SET TEXTMERGE ON
  472. ENDIF
  473.  
  474. *
  475. * VALIDPARAMS - Validate generator parameters.
  476. *
  477. * Description:
  478. * Attempt to open the project database.  If error encountered then
  479. * on error routine takes over and issues 'CANCEL'.  The output file
  480. * cannot be erased, name not known.
  481. *
  482. FUNCTION validparams
  483. SELECT 0
  484. m.g_projalias = IIF(USED("projdbf"),"P"+;
  485.    SUBSTR(LOWER(SYS(3)),2,8),"projdbf")
  486. USE (m.projdbf) ALIAS (m.g_projalias) AGAIN
  487. IF versnum() > "2.5"
  488.    SET NOCPTRANS TO devinfo, symbols, OBJECT
  489. ENDIF
  490. m.g_errlog = stripext(m.projdbf)
  491. m.g_projpath = SUBSTR(m.projdbf,1,RAT("\",m.projdbf))
  492. IF FCOUNT() <> c_pjxflds
  493.    DO errorhandler WITH c_err_badgendate_LOC,LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  494.    RETURN .F.
  495. ENDIF
  496. GOTO RECORD m.recno
  497. m.g_outfile = ALLTRIM(SUBSTR(outfile,1,AT(c_null,outfile)-1))
  498. m.g_outfile = FULLPATH(m.g_outfile, m.g_projpath)
  499. IF _MAC AND RIGHT(m.g_outfile,1) = ":"
  500.    m.g_outfile = m.g_outfile + justfname(SUBSTR(outfile,1,AT(c_null,outfile)-1))
  501. ENDIF
  502. g_mnxfile[1] = FULLPATH(ALLTRIM(name), m.g_projpath)
  503. IF _MAC AND RIGHT(g_mnxfile[1],1) = ":"
  504.    g_mnxfile[1] = g_mnxfile[1] + justfname(name)
  505. ENDIF
  506. g_mnxfile[2] = basename(g_mnxfile[1])  
  507. * No ! in menu name [Rev: 6][BEG]
  508. IF "!" $ g_mnxfile[2]
  509.    DO errorhandler WITH c_err_nobangallowed_LOC, LINENO(), c_error_3 
  510. ENDIF   
  511. * No ! in menu name [Rev: 6][END]
  512.  
  513.  
  514. *
  515. * REFRESHPREFS - Refresh comment style and developer preferences.
  516. *
  517. * Description:
  518. * Get the newest preferences for documentation style and developer
  519. * data from the project database.
  520. *
  521. FUNCTION refreshprefs
  522. PRIVATE m.start, m.savrecno
  523. m.savrecno = RECNO()
  524. LOCATE FOR TYPE = "H"
  525. IF NOT FOUND ()
  526.    DO errorhandler WITH c_err_badrechead_LOC + m.g_projdbf,;
  527.       LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  528.    GOTO RECORD m.savrecno
  529.    RETURN
  530. ENDIF
  531. m.g_homedir = ALLTRIM(SUBSTR(homedir,1,AT(c_null,homedir)-1))
  532.  
  533. IF (RIGHT(m.g_homedir, 1) == "\")
  534.    m.g_homedir = m.g_homedir + "\"
  535. ENDIF
  536. m.start = 1
  537. m.g_devauthor = subdevinfo(m.start,c_authorlen,m.g_devauthor)
  538. m.start = m.start + c_authorlen + 1
  539. m.g_devcompany = subdevinfo(m.start,c_complen,m.g_devcompany)
  540. m.start = m.start + c_complen + 1
  541. m.g_devaddress = subdevinfo(m.start,c_addrlen,m.g_devaddress)
  542. m.start = m.start + c_addrlen + 1
  543. m.g_devcity = subdevinfo(m.start,c_citylen,m.g_devcity)
  544. m.start = m.start + c_citylen + 1
  545. m.g_devstate = subdevinfo(m.start,c_statlen,m.g_devstate)
  546. m.start = m.start + c_statlen + 1
  547. m.g_devzip = subdevinfo(m.start,c_ziplen,m.g_devzip)
  548. m.start = m.start + c_ziplen + 1
  549. m.g_devctry = subdevinfo(m.start,c_countrylen,m.g_devctry)
  550. IF cmntstyle = 0
  551.    m.g_corn1 = chr(214)
  552.    m.g_corn2 = chr(183)
  553.    m.g_corn3 = chr(211)
  554.    m.g_corn4 = chr(189)
  555.    m.g_corn5 = chr(199)
  556.    m.g_corn6 = chr(182)
  557.    m.g_horiz = chr(196)
  558.    m.g_verti1 = chr(186)
  559.    m.g_verti2 = chr(186)
  560. ENDIF
  561. GOTO RECORD m.savrecno
  562.  
  563. *
  564. * SUBDEVINFO - Substring the DEVINFO memo filed.
  565. *
  566. FUNCTION subdevinfo
  567. PARAMETER m.start, m.stop, m.default
  568. PRIVATE m.string
  569. m.string = SUBSTR(devinfo, m.start, m.stop+1)
  570. m.string = SUBSTR(m.string, 1, AT(c_null,m.string)-1)
  571. RETURN IIF(EMPTY(m.string), m.default, m.string)
  572.  
  573. ******************************************************************************
  574. *
  575. * Menu Code Generator's Main Module.
  576. *
  577. ******************************************************************************
  578.  
  579. *
  580. * BUILD - Generate code for a menu.
  581. *
  582. * Description:
  583. * Call BUILDENABLE to open .MNX database specified by the user.
  584. * If the above is successfully accomplished, then proceed to generate
  585. * the menu code.  After the menu code is generated, call BUILDDISABLE
  586. * to disable code generation between SET TEXTMERGE ON and
  587. * SET TEXTMERGE OFF.
  588. *
  589. FUNCTION BUILD
  590. IF NOT buildenable()
  591.    RETURN
  592. ENDIF
  593. DO acttherm WITH c_msg_genmenucode_LOC   && Localization support [Rev: 2][MOD]
  594. DO updtherm WITH 10
  595. DO getmenutype
  596. DO header
  597. DO gensetupcleanup WITH "setup"
  598. DO definemenu
  599. DO definepopups
  600. DO updtherm WITH 75
  601. DO globaldefaults
  602. DO updtherm WITH 95
  603. DO gensetupcleanup WITH "cleanup"
  604. DO genprocedures
  605.  
  606. IF m.g_graphic
  607.    SET MESSAGE TO c_msg_gencomplete_LOC   && Localization support [Rev: 2][MOD]
  608. ENDIF
  609. DO builddisable
  610. DO updtherm WITH 100
  611. DO deactthermo
  612.  
  613. *
  614. * BUILDENABLE - Enable code generation.
  615. *
  616. * Description:
  617. * Call opendb to open .MNX database.
  618. * Call openfile to open file to hold the generated program.
  619. * If error(s) encountered in opendb or openfile then don't do
  620. * anything and exit, otherwise enable code generation with the
  621. * SET TEXTMERGE ON command.
  622. *
  623. * Returns:
  624. * .T. on success; .F. on failure
  625. *
  626. FUNCTION buildenable
  627. PRIVATE m.stat, m.stat2
  628. m.stat = opendb(g_mnxfile[1]) AND openfile()
  629. IF m.stat
  630.    SET TEXTMERGE ON
  631. ENDIF
  632. RETURN m.stat
  633.  
  634. *
  635. * BUILDDISABLE - Disable code generation.
  636. *
  637. * Description:
  638. * Issue the command SET TEXTMERGE OFF.
  639. * Close the generated menu code output file.
  640. * If anything goes wrong display appropriate message to the user.
  641. *
  642. FUNCTION builddisable
  643. SET ESCAPE OFF
  644. ON ESCAPE
  645. SET TEXTMERGE OFF
  646. IF NOT FCLOSE(_TEXT)
  647.    DO errorhandler WITH c_err_nocloseapp_LOC, LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  648. ENDIF
  649.  
  650. *
  651. * OPENDB - Prepare database for processing.
  652. *
  653. * Description:
  654. * Attempt to USE a database.  If attempt fails and error is reported
  655. * call ERRORHANDLER routine to display a friendly message.  Return
  656. * with a status of .F..  If attempt succeeds, return with status of .T.
  657. *
  658. * Returns:
  659. * .T. on success; .F. on failure
  660. *
  661. FUNCTION opendb
  662. PARAMETER m.dbname
  663. PRIVATE m.dbalias
  664. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_2
  665. m.dbalias = LEFT(basename(m.dbname),c_aliaslen)
  666. IF USED (m.dbalias)
  667.    SELECT (m.dbalias)
  668.    IF RAT(".MNX",DBF())<>0
  669.       g_mnxfile[3] = .F.
  670.       g_mnxfile[4] = m.dbalias
  671.    ELSE
  672.       g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  673.       SELECT 0
  674.       USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  675.       g_mnxfile[3] = .T.
  676.    ENDIF
  677. ELSE
  678.    IF illegalname(m.dbalias)
  679.       g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  680.    ELSE
  681.       g_mnxfile[4] = m.dbalias
  682.    ENDIF
  683.    SELECT 0
  684.    USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  685.    g_mnxfile[3] = .T.
  686. ENDIF
  687. IF FCOUNT() <> c_mnxflds
  688.    IF FCOUNT() = c_20mnxflds
  689.       m.g_20mnx = .T.
  690.    ELSE
  691.       DO errorhandler WITH c_err_badmnxpre_LOC + m.dbalias + c_err_badmnxpost_LOC, ;
  692.          LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  693.       RETURN .F.
  694.    ENDIF
  695. ELSE
  696.    m.g_20mnx = .F.
  697. ENDIF
  698. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  699. IF m.g_error = .T.
  700.    RETURN .F.
  701. ENDIF
  702.  
  703. *
  704. * ILLEGALNAME - Check if default alias will be used when this
  705. *               database is USEd. (i.e., 1st letter is not A-Z,
  706. *                a-z or '_', or any one of ramaining letters is not
  707. *                alphanumeric.)
  708. *
  709. FUNCTION illegalname
  710. PARAMETER m.menuname
  711. PRIVATE m.start, m.aschar, m.length
  712. m.length = LEN(m.menuname)
  713. m.start  = 0
  714. IF m.length = 1
  715.    *
  716.    * If length 1, then check if default alias can be used,
  717.    * i.e., name is different than A-J and a-j.
  718.    *
  719.    m.aschar = ASC(m.menuname)
  720.    IF (m.aschar >= 65 AND m.aschar <= 74) OR ;
  721.          (m.aschar >= 97 AND m.aschar <= 106)
  722.       RETURN .T.
  723.    ENDIF
  724. ENDIF
  725. DO WHILE m.start < m.length
  726.    m.start  = m.start + 1
  727.    m.aschar = ASC(SUBSTR(m.menuname, m.start, 1))
  728.    IF m.start<>1 AND (m.aschar >= 48 AND m.aschar <= 57)
  729.       LOOP
  730.    ENDIF
  731.    IF NOT ((m.aschar >= 65 AND m.aschar <= 90) OR ;
  732.          (m.aschar >= 97 AND m.aschar <= 122) OR m.aschar = 95)
  733.       RETURN .T.
  734.    ENDIF
  735. ENDDO
  736. RETURN .F.
  737.  
  738. *
  739. * OPENFILE - Create and open the application output file.
  740. *
  741. * Description:
  742. * Create a file that will hold the generated menu code.
  743. * Open the newly created file.  If error(s) encountered
  744. * at any time issue an error message and return .F.
  745. *
  746. * Returns:
  747. * .T. on success; .F. on failure
  748. *
  749. FUNCTION openfile
  750. PRIVATE m.msg
  751. _TEXT = FCREATE(m.g_outfile)
  752. IF (_TEXT = -1)
  753.    m.msg = c_err_nofileopen_LOC + m.g_outfile   && Localization support [Rev: 2][MOD]
  754.    DO errorhandler WITH m.msg, LINENO(), c_error_3
  755.    m.g_nohandle = .T.
  756.    RETURN .F.
  757. ENDIF
  758. m.g_nohandle = .F.
  759.  
  760. *
  761. * DEFINEMENU - Define main menu and its pads.
  762. *
  763. * Description:
  764. * Issue DEFINE MENU ... command.
  765. * Call a procedure to define all menu pads.
  766. * Call a procedure to generate ON PAD statements when appropriate.
  767. *
  768. FUNCTION definemenu
  769. IF m.g_graphic
  770.    SET MESSAGE TO c_msg_genmenudefs_LOC   && Localization support [Rev: 2][MOD]
  771. ENDIF
  772. DO commentblock WITH "menu"
  773. SELECT (g_mnxfile[4])
  774.  
  775. IF m.g_shortcut    
  776.     RETURN    && skip if shortcut menu
  777. ENDIF
  778.  
  779. LOCATE FOR objtype = c_menu
  780. IF EOF()
  781.     * using Top-Level menu instead
  782.     LOCATE FOR objtype = c_sdimenu
  783. ENDIF
  784. m.g_location = location
  785.  
  786. m.g_padloca  = ALLTRIM(name)
  787. LOCATE FOR objtype = c_submenu AND objcode = c_global
  788. m.g_menucolor = SCHEME
  789. m.g_menumark  = MARK
  790.  
  791. DO CASE
  792. CASE m.g_inform AND m.g_location = c_replace
  793.     \DEFINE MENU (m.cMenuName) IN (m.oFormRef.Name) BAR
  794. CASE m.g_inform
  795.     \LOCAL lHasNewMenu
  796.     \lHasNewMenu = (TYPE("CNTPAD(m.cMenuName)") # "N")
  797.     \IF m.lHasNewMenu
  798.     \    DEFINE MENU (m.cMenuName) IN (m.oFormRef.Name) BAR
  799.     \ENDIF
  800. CASE (m.g_location >= 4 OR m.g_location=c_replace)
  801.     * Special BiDi handling
  802.     IF (m.g_location >= 4)
  803.         m.g_location = m.g_location - 4 
  804.         IF sys(4015)=1
  805.             \SET SYSMENU TO RTLJUSTIFY
  806.         ENDIF
  807.     ENDIF
  808.     IF m.g_location = c_replace
  809.         \SET SYSMENU TO
  810.         \SET SYSMENU AUTOMATIC
  811.     ENDIF
  812. ENDCASE
  813.  
  814. \
  815. DO updtherm WITH 25
  816. DO defmenupads
  817. DO updtherm WITH 35
  818. DO defonpad
  819. \
  820. DO updtherm WITH 45
  821.  
  822. *
  823. * DEFMENUPADS - Define all pads for the menu bar.
  824. *
  825. * Description:
  826. * Scan the menu database for all objects of the type item which
  827. * have the levelname=_MSYSMENU.
  828. * For each such item, generate a statement DEFINE PAD... where
  829. * the name of the pad is the contents of NAME field or (if Name
  830. * field is empty) an automatically generated name.
  831. * Call procedures addkey, addskipfor, and mark to generate
  832. * KEY, SKIPFOR, or MARK clauses when appropriate.
  833. *
  834. FUNCTION defmenupads
  835. PRIVATE m.padname, m.prompt
  836. LOCAL lcNegotiate    && Add support for OLE2 Negotiate [Rev: 2][MOD]
  837. LOCAL lcNegContainer && Add support for ActiveDoc Negotiate
  838. LOCAL lcNegObject     && Add support for ActiveDoc Negotiate
  839. SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  840.    IF NOT EMPTY(ALLTRIM(name))
  841.       g_pads[VAL(Itemnum)] = name
  842.    ELSE
  843.       g_pads[VAL(Itemnum)] = LOWER(SYS(2015))
  844.    ENDIF
  845.    DO CASE 
  846.    CASE m.g_inform
  847.            \DEFINE PAD <<g_pads[VAL(Itemnum)]>> OF (m.cMenuName)
  848.    OTHERWISE
  849.            \DEFINE PAD <<g_pads[VAL(Itemnum)]>> OF _MSYSMENU
  850.    ENDCASE
  851.    IF MOD(VAL(itemnum),25)=0
  852.       DIMENSION g_pads[VAL(Itemnum)+25]
  853.    ENDIF
  854.    m.prompt = SUBSTR(PROMPT,1,LEN(PROMPT))
  855.    \\ PROMPT "<<m.prompt>>"
  856.    \\ COLOR SCHEME <<m.g_menucolor>>
  857.  
  858.    IF m.g_menumark<>c_null AND m.g_menumark<>""
  859.       \\ ;
  860.       \    MARK "<<m.g_menumark>>"
  861.    ENDIF
  862.  
  863.    DO CASE
  864.       CASE m.g_location = c_before
  865.          \\ ;
  866.          \    BEFORE <<m.g_padloca>>
  867.       CASE m.g_location = c_after
  868.          \\ ;
  869.          \    AFTER
  870.          IF VAL(itemnum) = 1
  871.             \\ <<m.g_padloca>>
  872.          ELSE
  873.             \\ <<g_pads[VAL(Itemnum)-1]>>
  874.          ENDIF
  875.    ENDCASE
  876.    * Add support for OLE2 Negotiate [Rev: 2][BEG]
  877.    *    c_neg_flag is a quote delimited constant for the field that must be evaluated
  878.    *    for a legal negotiate value.
  879.    lcNegotiate = EVAL( c_neg_flag )
  880.    IF NOT EMPTY( m.lcNegotiate )
  881.       m.lcNegContainer = BITAND(m.lcNegotiate, 0x000F)
  882.       m.lcNegObject = BITRSHIFT(BITAND(m.lcNegotiate, 0x00F0), 4)
  883.       \\ ;
  884.       \    NEGOTIATE 
  885.       DO CASE
  886.          CASE m.lcNegContainer = c_neg_none
  887.             \\ NONE,
  888.          CASE m.lcNegContainer = c_neg_left
  889.             \\ LEFT,
  890.          CASE m.lcNegContainer = c_neg_middle
  891.             \\ MIDDLE,
  892.          CASE m.lcNegContainer = c_neg_right
  893.             \\ RIGHT,
  894.          OTHERWISE
  895.             DO errorhandler WITH c_err_badnegoval_LOC + c_neg_flag ,;
  896.                LINENO(),c_error_2   && Localization support [Rev: 2][MOD]
  897.       ENDCASE
  898.       DO CASE
  899.          CASE m.lcNegObject = c_neg_none
  900.             \\ NONE
  901.          CASE m.lcNegObject = c_neg_left
  902.             \\ LEFT
  903.          CASE m.lcNegObject = c_neg_middle
  904.             \\ MIDDLE
  905.          CASE m.lcNegObject = c_neg_right
  906.             \\ RIGHT
  907.          OTHERWISE
  908.             DO errorhandler WITH c_err_badnegoval_LOC + c_neg_flag ,;
  909.                LINENO(),c_error_2   && Localization support [Rev: 2][MOD]
  910.       ENDCASE
  911.    ENDIF
  912.    RELEASE m.negotiate
  913.    * Add support for OLE2 Negotiate [Rev: 2][END]
  914.    DO addkey
  915.    DO addskipfor
  916.    DO addmessage
  917. ENDSCAN
  918.  
  919.  
  920. *
  921. * DEFONPAD - Generate ON PAD... statements.
  922. *
  923. * Description:
  924. * Generate ON PAD statements for each pad off of the main menu which
  925. * has a submenu associated with it.
  926. * For pads which have no submenus, but there is a command associated
  927. * with them, issue ON SELECTION PAD... statements.  If the code
  928. * associated with a pad is a snippet, then issue a call to the
  929. * generated procedure and place the snippet code in it.
  930. *
  931. FUNCTION defonpad
  932. PRIVATE m.padname
  933. SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  934.    IF NOT EMPTY(ALLTRIM(name))
  935.       m.padname = name
  936.    ELSE
  937.       m.padname = g_pads[VAL(Itemnum)]
  938.    ENDIF
  939.    m.therec = RECNO()
  940.    SKIP
  941.    IF objtype=c_submenu AND numitems<>0
  942.        IF m.g_inform
  943.           \ON PAD <<m.padname>> OF (m.cMenuName)
  944.           \\ ACTIVATE POPUP (a_menupops[<<ASCAN(g_apops,LOWER(Name))>>])
  945.        ELSE
  946.           \ON PAD <<m.padname>> OF _MSYSMENU
  947.           \\ ACTIVATE POPUP <<LOWER(Name)>>
  948.        ENDIF
  949.       GOTO m.therec
  950.    ELSE
  951.       GOTO m.therec
  952.       DO onselection WITH "pad", m.padname, '_MSYSMENU'
  953.    ENDIF
  954. ENDSCAN
  955.  
  956.  
  957.  
  958. *
  959. * DEFINEPOPUPS - Define popups and their bars.
  960. *
  961. * Description:
  962. * Scan the Menu database to find all objecttypes = submenu.
  963. * They all correspond to popups.  For each such object found, issue
  964. * command DEFINE POPUP....  Add MARK, KEY, and SKIP FOR clauses
  965. * if appropriate by calling procedures to handle these tasks.  Call
  966. * procedure Defbars to define all bars of each popup.
  967. *
  968. FUNCTION definepopups
  969. PRIVATE m.savrecno, m.popname, m.sch, m.firstpop,m.newpopname
  970. m.firstpop = .T.
  971. IF m.g_graphic
  972.    SET MESSAGE TO c_msg_genpopdefs_LOC   && Localization support [Rev: 2][MOD]
  973. ENDIF
  974. SCAN FOR objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU" ;
  975.       AND numitems <> 0
  976.    m.savrecno = RECNO()
  977.    m.popname  = ALLTRIM(LOWER(levelname))
  978.    m.newpopname = m.popname
  979.    m.sch = SCHEME
  980.    DO CASE
  981.    CASE m.g_shortcut AND m.firstpop 
  982.            * safeguard against system popups used for top popup name
  983.            IF LOWER(LEFT(Name,2))="_m"
  984.                * Use default name
  985.             STORE c_shortcutdef_loc TO m.newpopname,m.g_shortcutname
  986.            ELSE
  987.                m.g_shortcutname = LOWER(Name)
  988.            ENDIF
  989.         m.firstpop = .F.
  990.        \DEFINE POPUP <<m.g_shortcutname>> SHORTCUT RELATIVE FROM MROW(),MCOL()
  991.    CASE m.g_shortcut
  992.        \DEFINE POPUP <<LOWER(Name)>> SHORTCUT RELATIVE
  993.   CASE m.g_inform
  994.        \DEFINE POPUP (a_menupops[<<ASCAN(g_apops,LOWER(Name))>>]) MARGIN RELATIVE SHADOW
  995.        \\ COLOR SCHEME <<m.sch>>
  996.    OTHERWISE
  997.        \DEFINE POPUP <<LOWER(Name)>> MARGIN RELATIVE SHADOW
  998.        \\ COLOR SCHEME <<m.sch>>
  999.    ENDCASE
  1000.    DO addmark
  1001.    DO addkey
  1002.    DO defbars WITH m.popname, numitems, m.newpopname 
  1003.    DO defonbar WITH m.popname, m.newpopname 
  1004.    \
  1005.    GOTO RECORD m.savrecno
  1006. ENDSCAN
  1007.  
  1008.  
  1009. *
  1010. * DEFBARS - Define bars for each popup.
  1011. *
  1012. * Description:
  1013. * Scan the menu database for all objects of the type item whose
  1014. * name equals to the current popup name.
  1015. * For each such item, generate a statement DEFINE BAR....
  1016. * Call procedures addkey, addskipfor, and addmark to generate
  1017. * KEY, SKIPFOR, or MARK clauses when appropriate.
  1018. *
  1019. FUNCTION defbars
  1020. PARAMETER m.popname, m.howmany, m.newname
  1021. IF EMPTY(m.newname)
  1022.     m.newname = m.popname
  1023. ENDIF
  1024. PRIVATE m.itemno, m.prompt,m.name, m.cPopExpr
  1025. SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  1026.    m.itemno = ALLTRIM(itemnum)
  1027.    m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,LOWER(m.newname))))+"])", LOWER(m.newname))
  1028.    IF NOT EMPTY(ALLTRIM(name))
  1029.       m.name = name
  1030.       \DEFINE BAR <<m.name>> OF <<m.cPopExpr>>
  1031.    ELSE
  1032.       \DEFINE BAR <<m.itemno>> OF <<m.cPopExpr>>
  1033.    ENDIF
  1034.    m.prompt = SUBSTR(PROMPT, 1,LEN(PROMPT))
  1035.    \\ PROMPT "<<m.prompt>>"
  1036.    DO addmark
  1037.    DO addkey
  1038.    DO addskipfor
  1039.    DO addmessage
  1040.    IF VAL(m.itemno)=m.howmany
  1041.       RETURN
  1042.    ENDIF
  1043. ENDSCAN
  1044.  
  1045. *
  1046. * DEFONBAR - Generate ON BAR... statements.
  1047. *
  1048. * Description:
  1049. * Generate ON BAR statements for each popup.
  1050. * For bars which have no submenus, but there is a command associated
  1051. * with them, issue ON SELECTION BAR... statements.  If a snippet is
  1052. * associated with the code then generate a call statement to the
  1053. * generated procedure containing the snippet code.
  1054. *
  1055. FUNCTION defonbar
  1056. PARAMETER m.popname,m.newname
  1057. PRIVATE m.itemno,  m.cPopExpr ,  m.cPopExpr2 
  1058. IF EMPTY(m.newname)
  1059.     m.newname = m.popname
  1060. ENDIF
  1061. SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  1062.    IF EMPTY(ALLTRIM(name))
  1063.       m.itemno = ALLTRIM(itemnum)
  1064.    ELSE
  1065.       m.itemno = name
  1066.    ENDIF
  1067.    SKIP
  1068.    m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,LOWER(m.newname))))+"])", LOWER(m.newname))
  1069.    m.cPopExpr2 = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,LOWER(name))))+"])", LOWER(name))
  1070.  
  1071.    IF objtype=c_submenu AND numitems<>0
  1072.       \ON BAR <<m.itemno>> OF <<m.cPopExpr>>
  1073.       \\ ACTIVATE POPUP <<m.cPopExpr2>>
  1074.       SKIP -1
  1075.    ELSE
  1076.       SKIP -1
  1077.       DO onselection WITH "BAR", m.itemno, m.newname
  1078.    ENDIF
  1079. ENDSCAN
  1080.  
  1081. *
  1082. * GLOBALDEFAULTS - Generate global default statements
  1083. *
  1084. * Description:
  1085. * Search the menu database for information needed to generate any of
  1086. * the following commands:
  1087. * ON SELECTION MENU <name> DO <action>
  1088. * ON SELECTION POPUP ALL DO <action>
  1089. * ON SELECTION POPUP <name> DO <action>
  1090. * It is possible that none of the above mentioned statements will be
  1091. * generated.  It is also possible that the action is a snippet of
  1092. * code and a call to the generated procedure containing the snippet
  1093. * will be generated.
  1094. *
  1095. * First try to generate ON SELECTION MENU...
  1096. * Then try to generate ON POPUP ALL...
  1097. * Lastly, try to generate ON SELECTION POPUP...
  1098. *
  1099. FUNCTION globaldefaults
  1100. LOCATE FOR objtype = c_menu
  1101. LOCAL m.cPopExpr
  1102. m.mrk = MARK
  1103. IF FOUND() AND MARK <> ""
  1104.    IF MARK = c_null
  1105.       \SET MARK OF MENU _MSYSMENU TO " "
  1106.    ELSE
  1107.       \SET MARK OF MENU _MSYSMENU TO "<<Mark>>"
  1108.    ENDIF
  1109. ENDIF
  1110. IF FOUND() AND NOT EMPTY(PROCEDURE)
  1111.    \ON SELECTION MENU _MSYSMENU
  1112.    DO genproccall
  1113. ENDIF
  1114. LOCATE FOR objtype = c_submenu AND objcode = c_global
  1115. IF FOUND() AND NOT EMPTY(PROCEDURE)
  1116.    \ON SELECTION POPUP ALL
  1117.    DO genproccall
  1118. ENDIF
  1119. SCAN FOR (objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU";
  1120.       AND NOT EMPTY(PROCEDURE))
  1121.   m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,ALLTRIM(LOWER(Levelname)))))+"])", ALLTRIM(LOWER(Levelname)))
  1122.    \ON SELECTION POPUP <<m.cPopExpr>>
  1123.    DO genproccall
  1124. ENDSCAN
  1125.  
  1126.  
  1127. ******************************************************************************
  1128. *
  1129. * Subroutines for processing menu clause options.
  1130. *
  1131. ******************************************************************************
  1132. *
  1133. * ADDMARK - Generate a MARK clause whenever appropriate.
  1134. *
  1135. * Description:
  1136. * Add a MARK clause to the current PAD or BAR definition.
  1137. * If a field named Mark is not empty, then add the continuation
  1138. * character, ";", to the previous line, and then add the MARK... clause.
  1139. *
  1140. FUNCTION addmark
  1141. IF MARK<>c_null AND MARK<>""
  1142.    \\ ;
  1143.    \    MARK "<<Mark>>"
  1144. ENDIF
  1145.  
  1146.  
  1147.  
  1148. *
  1149. * ADDKEY - Generate KEY... clause whenever appropriate.
  1150. *
  1151. * Description:
  1152. * Add a KEY clause to the current PAD or BAR definition.
  1153. * If a field named Keyname is not empty, then add the continuation
  1154. * character, ";", to the previous line, and then add the KEY... clause.
  1155. *
  1156. FUNCTION addkey
  1157. * Add support for intelligent Pad hotkeys. [Rev: 7][BEG]
  1158. * NOTE: For consistency, Pads no longer respect keyname and 
  1159. *       keylabel, they use the letter following "\<" or the 
  1160. *       first letter of the prompt of none is defined.
  1161. LOCAL cKeyname, cKeylabel, nPosition
  1162. IF objtype=c_item AND ;
  1163.    UPPER(levelname)="_MSYSMENU" AND ;
  1164.    EMPTY(keyname)                          
  1165.    nPosition = AT_C("\<",prompt)
  1166.    IF m.nPosition > 0 AND NOT EMPTY(SUBSTRC(prompt,m.nPosition+2,1))
  1167.       STORE c_key_padhotkey_LOC + UPPER(SUBSTRC(prompt,m.nPosition+2,1)) TO m.cKeyname
  1168.    ELSE
  1169.       IF !IsLeadByte(prompt)
  1170.           STORE c_key_padhotkey_LOC + UPPER(LEFT(prompt,1)) TO m.cKeyname
  1171.       ELSE
  1172.           STORE "" to m.cKeyname
  1173.       ENDIF
  1174.    ENDIF
  1175.    cKeylabel = ""
  1176. ELSE 
  1177.    cKeyname  = keyname
  1178.    cKeylabel = keylabel
  1179. ENDIF   
  1180. IF NOT EMPTY(m.cKeyname)
  1181.    \\ ;
  1182.    \    KEY <<m.cKeyname>>, "<<m.cKeylabel>>"
  1183. ENDIF
  1184. * Add support for intelligent Pad hotkeys. [Rev: 7][END]
  1185.  
  1186.  
  1187.  
  1188. *
  1189. * ADDSKIPFOR - Generate SKIP FOR... clause whenever appropriate.
  1190. *
  1191. * Description:
  1192. * Add a ADDSKIPFOR clause to the current PAD or BAR definition.
  1193. * If a field named Addskipfor is not empty, then add the continuation
  1194. * character, ";", to the previous line, and then add the SKIP FOR...
  1195. * clause.
  1196. *
  1197. FUNCTION addskipfor
  1198. PRIVATE m.skip
  1199. m.skip = skipfor
  1200. IF NOT EMPTY(skipfor)
  1201.    \\ ;
  1202.    \    SKIP FOR <<m.skip>>
  1203. ENDIF
  1204.  
  1205.  
  1206.  
  1207. *
  1208. * ADDMESSAGE - Generate MESSAGE clause whenever appropriate.
  1209. *
  1210. * Description:
  1211. * Add a MESSAGE clause to the current PAD or BAR definition.
  1212. * If a field named MESSAGE is not empty and it is not a 2.0 menu,
  1213. * then add the continuation character, ";", to the previous line,
  1214. * and then add the MESSAGE clause.
  1215. *
  1216. FUNCTION addmessage
  1217. IF !m.g_20mnx AND NOT EMPTY(MESSAGE)
  1218.    \\ ;
  1219.    \    MESSAGE <<Message>>
  1220. ENDIF
  1221.  
  1222.  
  1223.  
  1224. *
  1225. * HEADER - Generate generated program's header.
  1226. *
  1227. * Description:
  1228. * As a part of the automatically generated program's header generate
  1229. * program name, name of the author of the program, copyright notice,
  1230. * company name and address, and the word 'Description:' which will be
  1231. * followed with a short description of the generated code.
  1232. *
  1233. FUNCTION HEADER
  1234. \\*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1235. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1236. \*       <<m.g_verti1>> <<DATE()>>
  1237. \\<<PADC(UPPER(ALLTRIM(strippath(m.g_outfile))),IIF(SET("CENTURY")="ON",35,37))," ")>>
  1238. \\ <<TIME()>>  <<m.g_verti2>>
  1239. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1240. \*       <<m.g_corn5>><<REPLICATE(m.g_horiz,57)>><<m.g_corn6>>
  1241. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1242. \*       <<m.g_verti1>> <<m.g_devauthor>>
  1243. \\<<REPLICATE(" ",max(1,56-LEN(m.g_devauthor)))>><<m.g_verti2>>
  1244. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1245. \*       <<m.g_verti1>>
  1246. *- Localization support [Rev: 2][MOD]
  1247. \\ c_hdr_copyright_LOC <<YEAR(DATE())>>
  1248. IF LEN(ALLTRIM(m.g_devcompany)) <= 36
  1249.    \\ <<ALLTRIM(m.g_devcompany)>>
  1250.    \\<<REPLICATE(" ",max(1,37-LEN(ALLTRIM(m.g_devcompany))))>>
  1251.    \\<<m.g_verti2>>
  1252. ELSE
  1253.    \\ <<REPLICATE(" ",37)>><<m.g_verti2>>
  1254.    \*       <<m.g_verti1>> <<m.g_devcompany>>
  1255.    \\<<REPLICATE(" ",max(1,56-LEN(m.g_devcompany)))>><<m.g_verti2>>
  1256. ENDIF
  1257.  
  1258. \*       <<m.g_verti1>> <<m.g_devaddress>>
  1259. \\<<REPLICATE(" ",max(1,56-LEN(m.g_devaddress)))>><<m.g_verti2>>
  1260.  
  1261. \*       <<m.g_verti1>> <<ALLTRIM(m.g_devcity)>>, <<m.g_devstate>>
  1262. \\  <<ALLTRIM(m.g_devzip)>>
  1263. \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devcity)+ALLTRIM(m.g_devzip))))>>
  1264. \\<<m.g_verti2>>
  1265.  
  1266. IF !INLIST(ALLTRIM(UPPER(m.g_devctry)),"USA","COUNTRY") AND !EMPTY(m.g_devctry)
  1267.    \*       <<m.g_verti1>> <<ALLTRIM(m.g_devctry)>>
  1268.    \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devctry))))>>
  1269.    \\<<m.g_verti2>>
  1270. ENDIF
  1271. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1272. *- Localization support [Rev: 2][MOD]
  1273. \*       <<m.g_verti1>> c_hdr_descript_LOC
  1274. \\                                            <<m.g_verti2>>
  1275. \*       <<m.g_verti1>>
  1276. *- Localization support [Rev: 2][MOD]
  1277. \\ c_hdr_string_LOC
  1278. \\    <<m.g_verti2>>
  1279. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1280. \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1281. \
  1282.  
  1283.  
  1284.  
  1285. *
  1286. * GENFUNCHEADER - Generate Comment for Function/Procedure.
  1287. *
  1288. FUNCTION genfuncheader
  1289. PARAMETER m.procname
  1290. PRIVATE m.place, m.prompt
  1291. m.g_snippcnt = m.g_snippcnt + 1
  1292. DO CASE
  1293.    CASE objtype = c_menu
  1294.       m.place = "ON SELECTION MENU _MSYSMENU"
  1295.    CASE objtype = c_submenu AND objcode = c_global
  1296.       m.place = "ON SELECTION POPUP ALL"
  1297.    CASE objtype = c_submenu AND objcode <> c_global
  1298.       m.place = "ON SELECTION POPUP "+LOWER(ALLTRIM(name))
  1299.    CASE objtype = c_item AND UPPER(levelname) = "_MSYSMENU"
  1300.       m.place = "ON SELECTION PAD "
  1301.    CASE objtype = c_item AND UPPER(levelname) <> "_MSYSMENU"
  1302.       m.place = "ON SELECTION BAR "+ALLTRIM(itemnum)+;
  1303.          +" OF POPUP "+LOWER(ALLTRIM(levelname))
  1304.    OTHERWISE
  1305.       m.place = ""
  1306. ENDCASE
  1307. \
  1308. \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1309. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1310. \*       <<m.g_verti1>> <<UPPER(PADR(m.procname,10))>>  <<m.place>>
  1311. \\<<REPLICATE(" ",max(1,max(1,44-LEN(m.place))))>><<m.g_verti2>>
  1312. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1313. \*       <<m.g_verti1>> Procedure Origin:
  1314. \\<<REPLICATE(" ",39)>><<m.g_verti2>>
  1315. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1316. \*       <<m.g_verti1>> From Menu:
  1317. \\  <<ALLTRIM(strippath(m.g_outfile))>>
  1318. \\,            Record:  <<STR(RECNO(),3)>>
  1319. \\<<REPLICATE(" ",max(1,max(1,22-LEN(ALLTRIM(strippath(m.g_outfile))+STR(RECNO(),3))))))>>
  1320. \\<<m.g_verti2>>
  1321. \*       <<m.g_verti1>> Called By:  <<m.place>>
  1322. \\<<REPLICATE(" ",max(1,max(1,44-LEN(m.place))))>><<m.g_verti2>>
  1323. IF NOT EMPTY(PROMPT)
  1324.    m.prompt = removemeta()
  1325.    \*       <<m.g_verti1>> Prompt:     <<ALLTRIM(m.prompt)>>
  1326.    \\<<REPLICATE(" ",max(1,44-LEN(ALLTRIM(m.prompt))))>><<m.g_verti2>>
  1327. ENDIF
  1328. \*       <<m.g_verti1>> Snippet:
  1329. \\    <<ALLTRIM(STR(m.g_snippcnt,2))>>
  1330. \\<<REPLICATE(" ",max(1,44-LEN(ALLTRIM(STR(m.g_snippcnt,2)))))>><<m.g_verti2>>
  1331. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1332. \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1333. \*
  1334.  
  1335.  
  1336.  
  1337. *
  1338. * REMOVEMETA - Remove meta characters for documentation.
  1339. *
  1340. FUNCTION removemeta
  1341. PRIVATE m.prompt, m.hotkey
  1342. m.prompt = PROMPT
  1343. m.hotkey = AT("\<",m.prompt)
  1344. IF m.hotkey <> 0
  1345.    m.prompt = STUFF(m.prompt,m.hotkey,2,"")
  1346. ENDIF
  1347. m.disabl = AT("\",m.prompt)
  1348. IF m.disabl <> 0
  1349.    m.prompt = STUFF(m.prompt,m.disabl,1,"")
  1350. ENDIF
  1351. RETURN m.prompt
  1352.  
  1353.  
  1354. *
  1355. * COMMENTBLOCK - Generate a comment block.
  1356. *
  1357. FUNCTION commentblock
  1358. PARAMETER m.snippet
  1359. \
  1360. \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1361. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1362. DO CASE
  1363.    CASE m.snippet == "setup"
  1364.       \*       <<m.g_verti1>>
  1365.       *- Localization support [Rev: 2][MOD]
  1366.       \\ <<PADC( c_snip_setup_LOC ,56," ")>>
  1367.    CASE m.snippet == "cleanup"
  1368.       \*       <<m.g_verti1>>
  1369.       *- Localization support [Rev: 2][MOD]
  1370.       \\ <<PADC( c_snip_cleanup_LOC ,56," ")>>
  1371.    CASE m.snippet == "init"
  1372.       \*       <<m.g_verti1>>
  1373.       *- Localization support [Rev: 2][MOD]
  1374.       \\ <<PADC( c_snip_init_LOC ,56," ")>>
  1375.    CASE m.snippet == "menu"
  1376.       \*       <<m.g_verti1>>
  1377.       *- Localization support [Rev: 2][MOD]
  1378.       \\ <<PADC( c_snip_menu_LOC ,56," ")>>
  1379. ENDCASE
  1380. \\<<m.g_verti2>>
  1381. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1382. \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1383. \*
  1384. \
  1385.  
  1386. *
  1387. * ONSELECTION - Generate ON SELECTION... statements for menu items.
  1388. *
  1389. * Description:
  1390. * For pads and bars which have no submenu associated with them but
  1391. * instead have a non-empty Command field in the database, issue
  1392. * the ON SELECTION <command> statements.  If a snippet is associated
  1393. * with a pad then issue a call statement to the generated procedure
  1394. * containing the snippet.  Generated snippet procedure will be
  1395. * appended to the end of the output file.
  1396. *
  1397. FUNCTION onselection
  1398. PARAMETER m.which, m.name, m.ofname
  1399. PRIVATE m.trimname, m.basename, m.commd, m.cPopExpr 
  1400. IF EMPTY(PROCEDURE) AND EMPTY(COMMAND)
  1401.    RETURN
  1402. ENDIF
  1403.  
  1404. DO CASE
  1405.    CASE m.which == "pad"
  1406.       \ON SELECTION PAD <<m.name>>
  1407.    CASE m.which == "BAR"
  1408.       \ON SELECTION <<m.which+" "+m.name>>
  1409. ENDCASE
  1410.  
  1411. IF m.g_inform AND !m.g_shortcut AND m.which#"BAR"
  1412.     \\ OF (m.cMenuName)
  1413. ELSE
  1414.     m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,m.ofname)))+"])",m.ofname)
  1415.     \\ OF <<m.cPopExpr>>
  1416. ENDIF
  1417.  
  1418. IF objcode = c_proc
  1419.    DO gensnippname
  1420.    m.trimname = SYS(2014,UPPER(m.g_outfile),UPPER(m.g_homedir))
  1421.    m.trimname = stripext(m.trimname)
  1422.    m.basename = basename(m.trimname)
  1423.    \\ ;
  1424.    \    DO <<g_snippets[g_nsnippets,1]>> ;
  1425.    \    IN LOCFILE("<<m.trimname>>"
  1426.    \\ ,"MPX;MPR|FXP;PRG"
  1427.    \\ ,"
  1428.    *- Localization support [Rev: 2][MOD]
  1429.    \\c_ui_whereis_LOC
  1430.    \\ <<m.basename>>?")
  1431. ELSE
  1432.    m.commd = COMMAND
  1433.    \\ <<m.commd>>
  1434. ENDIF
  1435.  
  1436.  
  1437.  
  1438. *
  1439. * GENSNIPPNAME - Generate a unique name for snippet procedure.
  1440. *
  1441. * Description:
  1442. * Lookup the #NAME name of this snippet, or alternatively
  1443. * provide a unique name for a snippet of code associated with the
  1444. * generated menu.  Save this name in an array g_snippets.
  1445. *
  1446. FUNCTION gensnippname
  1447. g_nsnippets = g_nsnippets + 1
  1448. g_snippets[g_nsnippets,1] = getcname(PROCEDURE)
  1449. g_snippets[g_nsnippets,2] = RECNO()
  1450. IF MOD(g_nsnippets,25) = 0
  1451.    DIMENSION g_snippets [g_nsnippets+25,2]
  1452. ENDIF
  1453.  
  1454.  
  1455.  
  1456. *
  1457. * GENPROCCALL - Generate a call statement to snippet procedure.
  1458. *
  1459. * Description:
  1460. * Generate a call to the snippet procedure in the menu definition
  1461. * code.
  1462. *
  1463. FUNCTION genproccall
  1464. PRIVATE m.trimname, m.basename, m.proc
  1465. IF singleline()
  1466.    m.proc = PROCEDURE
  1467.    \\ <<MLINE(m.proc,1)>>
  1468. ELSE
  1469.    DO gensnippname
  1470.    m.trimname = SYS(2014,UPPER(m.g_outfile),UPPER(m.g_homedir))
  1471.    m.trimname = stripext(m.trimname)
  1472.    m.basename = basename(m.trimname)
  1473.    \\ ;
  1474.    \    DO <<g_snippets[m.g_nsnippets,1]>> ;
  1475.    \    IN LOCFILE("<<m.trimname>>"
  1476.    \\ ,"MPX;MPR|FXP;PRG"
  1477.    \\ ,"
  1478.    *- Localization support [Rev: 2][MOD]
  1479.    \\c_ui_whereis_LOC
  1480.    \\ <<m.basename>>?")
  1481. ENDIF
  1482.  
  1483.  
  1484.  
  1485. *
  1486. * SINGLELINE - Determine if Memo contains only one line.
  1487. *
  1488. * Description:
  1489. * This procedure is used to decide if an ON SELECTION... statement
  1490. * and a snippet procedure will be needed (i.e., if more than one
  1491. * line of snippet code then its a snippet, otherwise its a command)
  1492. *
  1493. FUNCTION singleline
  1494. PRIVATE m.size, m.i
  1495. m.size = MEMLINES(PROCEDURE)
  1496. IF m.size = 1
  1497.    RETURN .T.
  1498. ENDIF
  1499. m.i = m.size
  1500. DO WHILE m.i > 1
  1501.    m.line = MLINE(PROCEDURE, m.i)
  1502.    IF NOT EMPTY(m.line)
  1503.       RETURN .F.
  1504.    ENDIF
  1505.    m.i = m.i - 1
  1506. ENDDO
  1507.  
  1508.  
  1509.  
  1510. *
  1511. * GENPROCEDURES - Generate procedure/snippet code.
  1512. *
  1513. * Description:
  1514. * Generate 'PROCEDURE procedurename' statement and its body.
  1515. *
  1516. FUNCTION genprocedures
  1517. PRIVATE m.i
  1518. IF m.g_graphic
  1519.    SET MESSAGE TO c_msg_genprocs_LOC   && Localization support [Rev: 2][MOD]
  1520. ENDIF
  1521. FOR m.i = 1 TO m.g_nsnippets
  1522.    GOTO RECORD (g_snippets[m.i,2])
  1523.    DO genfuncheader WITH g_snippets[m.i,1]
  1524.    \PROCEDURE <<g_snippets[m.i,1]>>
  1525.    DO writecode WITH PROCEDURE
  1526.    \
  1527. ENDFOR
  1528.  
  1529.  
  1530.  
  1531. *
  1532. * WRITECODE - Write contents of a memo to a low level file.
  1533. *
  1534. * Description:
  1535. * Receive a memo field as a parameter and write its contents out
  1536. * to the currently opened low level file whose handle is stored
  1537. * in the system memory variable _TEXT.  Contents of the system
  1538. * memory variable _pretext will affect the positioning of the
  1539. * generated text.
  1540. *
  1541. FUNCTION writecode
  1542. PARAMETER m.memo, m.codefield
  1543. PRIVATE m.lines, m.i, m.thisline, m.lHadActPopup
  1544. IF TYPE("m.codefield") # "C"
  1545.     m.codefield = ""
  1546. ENDIF
  1547. m.lHadActPopup = .F.
  1548. m.lines = MEMLINES(m.memo)
  1549. _MLINE = 0
  1550. FOR m.i = 1 TO m.lines
  1551.    m.thisline = MLINE(m.memo, 1, _MLINE)
  1552.    DO CASE
  1553.    CASE m.g_shortcut  AND m.codefield=="cleanup" AND  !m.lHadActPopup AND LEFT(UPPER(LTRIM(m.thisline)),5) == "#PREP"    && #PREPOPUP in Cleanup
  1554.     DO actpopup
  1555.     m.lHadActPopup = .T.
  1556.     m.g_prepopup = .F.
  1557.    CASE m.g_shortcut AND m.codefield#"cleanup" AND LEFT(UPPER(LTRIM(m.thisline)),5) == "#PREP"        && #PREPOPUP in Setup
  1558.     m.g_prepopup = .T.
  1559.    CASE LEFT(UPPER(LTRIM(m.thisline)),5) == "#INSE"   && #INSERT
  1560.         DO GenInsertCode WITH m.thisline
  1561.    CASE INLIST(LEFT(UPPER(LTRIM(m.thisline)),5) ,"#NAME","#PREP")    &&skip #PREP for non Shortcut menus
  1562.     * Do nothing
  1563.    OTHERWISE
  1564.          \<<m.thisline>>
  1565.    ENDCASE
  1566. ENDFOR
  1567.  
  1568.  
  1569.  
  1570. *
  1571. * GENSETUPCLEANUP - Generate setup/cleanup code.
  1572. *
  1573. FUNCTION GenSetupCleanup
  1574. PARAMETER m.choice
  1575. LOCATE FOR objtype = IIF(m.g_shortcut,c_shortcut,IIF(m.g_inform,c_sdimenu,c_menu))
  1576. DO CASE
  1577.    CASE m.choice == "setup"
  1578.       IF m.g_inform
  1579.          DO sdiheader
  1580.       ENDIF    
  1581.       IF EMPTY(setup)
  1582.          RETURN
  1583.       ENDIF
  1584.       IF m.g_graphic
  1585.          SET MESSAGE TO c_msg_gensetup_LOC   && Localization support [Rev: 2][MOD]
  1586.       ENDIF
  1587.       DO commentblock WITH m.choice
  1588.       DO writecode WITH setup
  1589.    CASE m.choice == "cleanup"
  1590.       IF !m.g_prepopup AND ATC("#PREP",cleanup)=0
  1591.               DO actpopup
  1592.       ENDIF
  1593.       IF !EMPTY(cleanup)
  1594.           IF m.g_graphic
  1595.              SET MESSAGE TO c_msg_gencleanup_LOC   && Localization support [Rev: 2][MOD]
  1596.           ENDIF
  1597.           DO commentblock WITH m.choice
  1598.           DO writecode WITH cleanup,m.choice
  1599.     ENDIF
  1600.       IF m.g_prepopup
  1601.               DO actpopup
  1602.       ENDIF
  1603. ENDCASE
  1604.  
  1605.  
  1606. *
  1607. * GENINSERTCODE - Emit code from the #insert file, if any
  1608. *
  1609. FUNCTION GenInsertCode
  1610. PARAMETER strg
  1611. PRIVATE m.word1, m.filname, m.ins_fp, m.buffer
  1612. IF UPPER(LEFT(LTRIM(m.strg),5)) == "#INSE"
  1613.    m.word1 = wordnum(m.strg,1)
  1614.    m.filname = SUBSTR(m.strg,LEN(m.word1)+1)
  1615.    m.filname = ALLTRIM(CHRTRAN(m.filname,CHR(9),""))
  1616.  
  1617.    * Bail out if we can't find the file either explicitly or on the DOS path
  1618.    IF !FILE(m.filname)
  1619.       filname = FULLPATH(m.filname,1)
  1620.       IF !FILE(m.filname)
  1621.          \*Insert file <<m.filname>> could not be found
  1622.          RETURN
  1623.       ENDIF
  1624.    ENDIF
  1625.  
  1626.    ins_fp = FOPEN(m.filname)
  1627.    IF ins_fp > 0
  1628.       \* Inserted from <<strippath(m.filname)>>
  1629.       DO WHILE !FEOF(ins_fp)
  1630.          m.buffer = FGETS(ins_fp)
  1631.          \<<m.buffer>>
  1632.       ENDDO
  1633.       =FCLOSE(m.ins_fp)
  1634.       \* End of inserted lines
  1635.    ENDIF
  1636. ENDIF
  1637.  
  1638.  
  1639. ******************************************************************************
  1640. *
  1641. * Code assocated with thermometer.
  1642. *
  1643. ******************************************************************************
  1644. *
  1645. * ACTTHERM(<text>) - Activate thermometer.
  1646. *
  1647. * Description:
  1648. * Activates thermometer.  Update the thermometer with UPDTHERM().
  1649. * Thermometer window is named "thermometer."  Be sure to RELEASE
  1650. * this window when done with thermometer.  Creates the global
  1651. * m.g_thermwidth.
  1652. *
  1653. FUNCTION acttherm
  1654. PARAMETER m.text
  1655. PRIVATE m.prompt
  1656. IF m.g_graphic
  1657.    m.prompt = m.g_outfile
  1658.    m.prompt = thermfname(m.prompt)
  1659.    DO CASE
  1660.       CASE _WINDOWS
  1661.            LOCAL cWinColor
  1662.            cWinColor = rgbscheme(1, 2)
  1663.          DEFINE WINDOW thermomete ;
  1664.             AT  INT((SROW() - (( 5.615 * ;
  1665.             FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1666.             FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
  1667.             INT((SCOL() - (( 63.833 * ;
  1668.             FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1669.             FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
  1670.             SIZE 5.615,63.833 ;
  1671.             FONT m.g_dlgface, m.g_dlgsize ;
  1672.             STYLE m.g_dlgstyle ;
  1673.             NOFLOAT ;
  1674.             NOCLOSE ;
  1675.             NONE ;
  1676.             COLOR &cWinColor 
  1677.          MOVE WINDOW thermomete CENTER
  1678.          ACTIVATE WINDOW thermomete NOSHOW
  1679.          @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
  1680.          @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
  1681.          @ 0.000,0.000 TO 0.000,63.833 ;
  1682.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1683.          @ 0.000,0.000 TO 5.615,0.000 ;
  1684.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1685.          @ 0.385,0.667 TO 5.231,0.667 ;
  1686.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1687.          @ 0.308,0.667 TO 0.308,63.167 ;
  1688.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1689.          @ 0.385,63.000 TO 5.308,63.000 ;
  1690.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1691.          @ 5.231,0.667 TO 5.231,63.167 ;
  1692.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1693.          @ 5.538,0.000 TO 5.538,63.833 ;
  1694.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1695.          @ 0.000,63.667 TO 5.615,63.667 ;
  1696.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1697.          @ 3.000,3.333 TO 4.231,3.333 ;
  1698.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1699.          @ 3.000,60.333 TO 4.308,60.333 ;
  1700.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1701.          @ 3.000,3.333 TO 3.000,60.333 ;
  1702.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1703.          @ 4.231,3.333 TO 4.231,60.333 ;
  1704.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1705.          m.g_thermwidth = 56.269
  1706.       CASE _MAC
  1707.          DEFINE WINDOW thermomete ;
  1708.             AT  INT((SROW() - (( 5.62 * ;
  1709.             FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1710.             FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
  1711.             INT((SCOL() - (( 63.83 * ;
  1712.             FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1713.             FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
  1714.             SIZE 5.62,63.83 ;
  1715.             FONT m.g_dlgface, m.g_dlgsize ;
  1716.             STYLE m.g_dlgstyle ;
  1717.             NOFLOAT ;
  1718.             NOCLOSE ;
  1719.             NONE ;
  1720.             COLOR RGB(0, 0, 0, 192, 192, 192)
  1721.          MOVE WINDOW thermomete CENTER
  1722.          ACTIVATE WINDOW thermomete NOSHOW
  1723.          @ 0.000,0.000 TO 5.62,63.83 PATTERN 1;
  1724.             COLOR RGB(192, 192, 192, 192, 192, 192)
  1725.          IF ISCOLOR()
  1726.             @ 0.000,0.000 TO 5.62,63.83 PATTERN 1;
  1727.                COLOR RGB(192, 192, 192, 192, 192, 192)
  1728.             @ 0.000,0.000 TO 0.000,63.83 ;
  1729.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1730.             @ 0.000,0.000 TO 5.62,0.000 ;
  1731.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1732.             @ 0.385,0.67 TO 5.23,0.67 ;
  1733.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1734.             @ 0.31,0.67 TO 0.31,63.17 ;
  1735.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1736.             @ 0.385,63.000 TO 5.31,63.000 ;
  1737.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1738.             @ 5.23,0.67 TO 5.23,63.17 ;
  1739.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1740.             @ 5.54,0.000 TO 5.54,63.83 ;
  1741.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1742.             @ 0.000,63.67 TO 5.62,63.67 ;
  1743.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1744.             @ 3.000,3.33 TO 4.23,3.33 ;
  1745.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1746.             @ 3.000,60.33 TO 4.31,60.33 ;
  1747.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1748.             @ 3.000,3.33 TO 3.000,60.33 ;
  1749.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1750.             @ 4.23,3.33 TO 4.23,60.33 ;
  1751.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1752.          ELSE
  1753.             @ 0.000, 0.000 TO 5.62, 63.830  PEN 2
  1754.             @ 0.230, 0.500 TO 5.39, 63.333  PEN 1
  1755.          ENDIF
  1756.          @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
  1757.             COLOR RGB(0,0,0,192,192,192)
  1758.          @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
  1759.             COLOR RGB(0,0,0,192,192,192)
  1760.  
  1761.          m.g_thermwidth = 56.27
  1762.          IF !ISCOLOR()
  1763.             @ 3.000,3.33 TO 4.23, (m.g_thermwidth + 1) + 3.33
  1764.          ENDIF
  1765.    ENDCASE
  1766.    SHOW WINDOW thermomete TOP
  1767. ELSE
  1768.    m.prompt = SUBSTR(SYS(2014,UPPER(m.g_outfile)),1,48)+;
  1769.       IIF(LEN(m.g_outfile)>48,"...","")
  1770.    DEFINE WINDOW thermomete;
  1771.       FROM INT((SROW()-6)/2), INT((SCOL()-57)/2) ;
  1772.       TO INT((SROW()-6)/2) + 6, INT((SCOL()-57)/2) + 57;
  1773.       DOUBLE COLOR SCHEME 5
  1774.    ACTIVATE WINDOW thermomete NOSHOW
  1775.    m.g_thermwidth = 50
  1776.    @ 0,3 SAY m.text
  1777.    @ 1,3 SAY UPPER(m.prompt)
  1778.    @ 2,1 TO 4,m.g_thermwidth+4 &g_boxstrg
  1779.    SHOW WINDOW thermomete TOP
  1780. ENDIF
  1781. RETURN
  1782.  
  1783.  
  1784. *
  1785. * UPDTHERM(<percent>) - Update thermometer.
  1786. *
  1787. FUNCTION updtherm
  1788. PARAMETER m.percent
  1789. PRIVATE m.nblocks, m.percent
  1790. ACTIVATE WINDOW thermomete
  1791. m.nblocks = (m.percent/100) * (m.g_thermwidth)
  1792. DO CASE
  1793.    CASE _WINDOWS
  1794.       @ 3.000,3.333 TO 4.231,m.nblocks + 3.333 ;
  1795.          PATTERN 1 COLOR RGB(128, 128, 128, 128, 128, 128)
  1796.    CASE _MAC
  1797.       @ 3.000,3.33 TO 4.23,m.nblocks + 3.33 ;
  1798.          PATTERN 1 COLOR RGB(0, 0, 128, 0, 0, 128)
  1799.    OTHERWISE
  1800.       @ 3,3 SAY REPLICATE("█",m.nblocks)
  1801. ENDCASE
  1802.  
  1803. *
  1804. * DEACTTHERMO - Deactivate and Release thermometer window.
  1805. *
  1806. FUNCTION deactthermo
  1807. RELEASE WINDOW thermomete
  1808.  
  1809.  
  1810. *
  1811. * Function: THERMFNAME
  1812. *
  1813. * [Rev: 8]
  1814. * Modified to use CutFileLoc() if name is too long.  
  1815. * Moved global variables to top of program.
  1816. * Merged thermometer window font info with dialogs.
  1817. FUNCTION thermfname
  1818. PARAMETER m.fname
  1819. IF TXTWIDTH(m.fname,m.g_dlgface,m.g_dlgsize,m.g_dlgstyle) > c_space
  1820.    m.fname = CutFileLoc(m.fname, c_space -1)
  1821. ENDIF
  1822. RETURN PROPER(m.fname)
  1823.  
  1824.  
  1825.  
  1826. ******************************************************************************
  1827. *
  1828. * Error Handling Code.
  1829. *
  1830. ******************************************************************************
  1831. *
  1832. * ERRORHANDLER - Error Processing Center.
  1833. *
  1834. FUNCTION errorhandler
  1835. PARAMETERS m.messg, m.lineno, m.code
  1836. IF ERROR() = 22  && Too many memory variables
  1837.    =MESSAGEBOX(c_err_toomanymemvars_LOC + REPL(c_CRLF,2) + c_msg_genstopped_LOC)    && Tell the user [Rev: 6][ADD]
  1838.    ON ERROR &onerror
  1839.    DO cleanup
  1840.    CANCEL       && Early exit
  1841. ENDIF
  1842. DO CASE
  1843.    CASE c_DEBUG   && Add debug mode [Rev: 4][BEG]
  1844.       =MESSAGEBOX(m.messg)
  1845.       SET DEBUG ON
  1846.       SET STEP ON
  1847.       * Add debug mode [Rev: 4][END]
  1848.    CASE m.code == c_error_1  && Minor
  1849.       DO errlog WITH m.messg, m.lineno
  1850.       DO errshow WITH m.messg, m.lineno, c_error_1Icon   && Show minor errors [Rev: 6][ADD]
  1851.       m.g_status = 1
  1852.    CASE m.code == c_error_2  && Serious
  1853.       DO errlog  WITH m.messg, m.lineno
  1854.       DO errshow WITH m.messg, m.lineno, c_error_2Icon   && Pass Error Icon [Rev: 6][ADD]
  1855.       m.g_error = .T.
  1856.       m.g_status = 2
  1857.       ON ERROR
  1858.    CASE m.code == c_error_3  && Fatal
  1859.       IF NOT m.g_nohandle
  1860.          DO errlog  WITH m.messg, m.lineno
  1861.       ENDIF
  1862.       WAIT WINDOW c_msg_genstopped_LOC NOWAIT   && Tell the user they are done. [Rev: 6][ADD]
  1863.       DO errshow WITH m.messg, m.lineno, c_error_3Icon   && Pass Error Icon [Rev: 6][ADD]
  1864.       WAIT CLEAR
  1865.       IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1866.          RELEASE WINDOW thermomete
  1867.       ENDIF
  1868.       ON ERROR
  1869.       DO cleanup
  1870.       CANCEL      && Early exit
  1871. ENDCASE
  1872. RETURN
  1873.  
  1874.  
  1875. *
  1876. * ESCHANDLER - Escape handler.
  1877. *
  1878. FUNCTION eschandler
  1879. ON ERROR
  1880. WAIT WINDOW c_msg_genstopped_LOC NOWAIT   && Localization support [Rev: 2][MOD]
  1881. DO builddisable
  1882. IF m.g_status > 0
  1883.    ERASE (m.g_outfile)
  1884. ENDIF
  1885. IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1886.    RELEASE WINDOW thermomete
  1887. ENDIF
  1888. DO cleanup
  1889. CANCEL      && Early exit
  1890.  
  1891.  
  1892. *
  1893. * ERRLOG - Insert error message into the error log.
  1894. *
  1895. FUNCTION errlog
  1896. PARAMETER m.messg, m.lineno
  1897. PRIVATE m.savehandle
  1898. m.savehandle = _TEXT
  1899. DO openerrfile
  1900. SET CONSOLE OFF
  1901.  
  1902. \\GENERATOR: <<ALLTRIM(m.messg)>>
  1903. IF NOT EMPTY(m.lineno)
  1904.    \\ LINE NUMBER: <<m.lineno>>
  1905. ENDIF
  1906. \
  1907. = FCLOSE(_TEXT)
  1908. _TEXT = m.savehandle
  1909. RETURN
  1910.  
  1911.  
  1912. *
  1913. * ERRSHOW - Display error message in the alert box.
  1914. *
  1915. FUNCTION errshow
  1916. PARAMETER m.msg, m.lineno, m.msgicon
  1917. PRIVATE m.curcursor
  1918. * Modify to utilize native MESSAGEBOX() function. [Rev: 6][BEG]
  1919. IF m.g_graphic
  1920.    m.msg = m.msg + REPL(c_CRLF,2) + ;
  1921.            c_err_lineno_LOC + STR(m.lineno, 4)  
  1922.    =MESSAGEBOX(m.msg, m.msgicon, c_err_title_LOC)
  1923. ELSE
  1924.    DEFINE WINDOW alert;
  1925.       FROM INT((SROW()-6)/2), INT((SCOL()-50)/2) TO INT((SROW()-6)/2) + 6, INT((SCOL()-50)/2) + 50 ;
  1926.       FLOAT NOGROW NOCLOSE NOZOOM    SHADOW DOUBLE;
  1927.       COLOR SCHEME 7
  1928.  
  1929.    ACTIVATE WINDOW alert
  1930.    @ 0,0 CLEAR
  1931.    @ 1,0 SAY PADC(SUBSTR(m.msg,1,44)+;
  1932.       IIF(LEN(m.msg)>44,"...",""), WCOLS())
  1933.    @ 2,0 SAY PADC(c_err_lineno_LOC + STR(m.lineno, 4), WCOLS())   && Localization support [Rev: 2][MOD]
  1934.    @ 3,0 SAY PADC(c_err_presskey_LOC, WCOLS())   && Localization support [Rev: 2][MOD]
  1935.    m.curcursor = SET( "CURSOR" )
  1936.    SET CURSOR OFF
  1937.    WAIT ""
  1938.    RELEASE WINDOW alert
  1939.    SET CURSOR &curcursor
  1940.    RELEASE WINDOW alert
  1941. ENDIF
  1942. * Modify to utilize native MESSAGEBOX() function. [Rev: 6][END]
  1943. RETURN
  1944.  
  1945.  
  1946.  
  1947. *
  1948. * OPENERRFILE - Open error file.
  1949. *
  1950. FUNCTION openerrfile
  1951. PRIVATE m.errfile, m.errhandle
  1952. m.errfile   = m.g_errlog+".ERR"
  1953. m.errhandle = FOPEN(m.errfile,2)
  1954. IF m.errhandle < 0
  1955.    m.errhandle = FCREATE(m.errfile)
  1956.    IF m.errhandle < 0
  1957.       DO errshow WITH c_err_noopenerr_LOC, LINENO()   && Localization support [Rev: 2][MOD]
  1958.       m.g_status = 2
  1959.       IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1960.          RELEASE WINDOW thermomete
  1961.       ENDIF
  1962.       ON ERROR
  1963.       RETURN TO MASTER
  1964.    ENDIF
  1965. ELSE
  1966.    = FSEEK(m.errhandle,0,2)
  1967. ENDIF
  1968. IF SET("TEXTMERGE") = "OFF"
  1969.    SET TEXTMERGE ON
  1970. ENDIF
  1971. _TEXT = m.errhandle
  1972.  
  1973.  
  1974.  
  1975. *
  1976. * GETCNAME - Manufacture a procedure name, unless there is a #NAME directive
  1977. *
  1978. FUNCTION getcname
  1979. PARAMETERS snippet
  1980. PRIVATE ALL
  1981. IF proctype = 1
  1982.    numlines = MEMLINES(snippet)
  1983.    IF m.numlines > 0
  1984.       _MLINE = 0
  1985.       m.i = 1
  1986.       DO WHILE m.i <= m.numlines
  1987.          m.thisline = UPPER(ALLTRIM(MLINE(snippet,1, _MLINE)))
  1988.          DO CASE
  1989.         CASE LEFT(m.thisline,5) == "#NAME"
  1990.                RETURN ALLTRIM(SUBSTR(m.thisline,6))
  1991.             CASE EMPTY(m.thisline) OR iscomment(m.thisline)
  1992.                * Do nothing.  Get next line.
  1993.             OTHERWISE
  1994.                EXIT
  1995.          ENDCASE
  1996.          m.i = m.i + 1
  1997.       ENDDO
  1998.    ENDIF
  1999. ENDIF
  2000. RETURN LOWER(SYS(2015))
  2001.  
  2002.  
  2003. *
  2004. * ISCOMMENT - Determine if textline is a comment line.
  2005. *
  2006. FUNCTION IsComment
  2007. PARAMETER m.textline
  2008. PRIVATE m.asterisk, m.isnote, m.ampersand, m.statement
  2009. IF EMPTY(m.textline)
  2010.    RETURN .F.
  2011. ENDIF
  2012. m.statement = UPPER(ALLTRIM(m.textline))
  2013.  
  2014. m.asterisk  = AT("*", LEFT(m.statement,1))
  2015. m.ampersand = AT(CHR(38)+CHR(38), LEFT(m.statement,2))
  2016. m.isnote    = AT("NOTE", LEFT(m.statement,4))
  2017. DO CASE
  2018.    CASE (m.asterisk = 1 OR m.ampersand = 1)
  2019.       RETURN .T.
  2020.    CASE (m.isnote = 1 ;
  2021.          AND (LEN(m.statement) <= 4 OR SUBSTR(m.statement,5,1) = ' '))
  2022.       * Don't be fooled by something like "notebook = 7"
  2023.       RETURN .T.
  2024. ENDCASE
  2025. RETURN .F.
  2026.  
  2027.  
  2028. *
  2029. * WORDNUM - Returns w_num-th word from string strg
  2030. *
  2031. FUNCTION wordnum
  2032. PARAMETERS strg,w_num
  2033. PRIVATE strg,s1,w_num,ret_str
  2034. m.s1 = ALLTRIM(m.strg)
  2035. * Replace tabs with spaces
  2036. m.s1 = CHRTRAN(m.s1,CHR(9)," ")
  2037. * Reduce multiple spaces to a single space
  2038. DO WHILE AT('  ',m.s1) > 0
  2039.    m.s1 = STRTRAN(m.s1,'  ',' ')
  2040. ENDDO
  2041. ret_str = ""
  2042. DO CASE
  2043.    CASE m.w_num > 1
  2044.       DO CASE
  2045.          CASE AT(" ",m.s1,m.w_num-1) = 0   && No word w_num.  Past end of string.
  2046.             m.ret_str = ""
  2047.          CASE AT(" ",m.s1,m.w_num) = 0     && Word w_num is last word in string.
  2048.             m.ret_str = SUBSTR(m.s1,AT(" ",m.s1,m.w_num-1)+1,255)
  2049.          OTHERWISE                         && Word w_num is in the middle.
  2050.             m.strt_pos = AT(" ",m.s1,m.w_num-1)
  2051.             m.ret_str  = SUBSTR(m.s1,strt_pos,AT(" ",m.s1,m.w_num)+1 - strt_pos)
  2052.       ENDCASE
  2053.    CASE m.w_num = 1
  2054.       IF AT(" ",m.s1) > 0               && Get first word.
  2055.          m.ret_str = SUBSTR(m.s1,1,AT(" ",m.s1)-1)
  2056.       ELSE                              && There is only one word.  Get it.
  2057.          m.ret_str = m.s1
  2058.       ENDIF
  2059. ENDCASE
  2060. RETURN ALLTRIM(m.ret_str)
  2061.  
  2062.  
  2063. *
  2064. * VERSNUM - Return string corresponding to FoxPro version number
  2065. *
  2066. FUNCTION versnum
  2067. RETURN STRTRAN(SUBS(VERS(),AT(".",VERS())-2),"0","",1,1)
  2068.  
  2069. PROCEDURE sdiheader
  2070. \* To attach this menu to your Top-Level form, 
  2071. \* call it from the Init event of the form:
  2072. \
  2073. \* Syntax: DO <mprname> WITH <oFormRef> [,<cMenuname>|<lRename>][<lUniquePopups>]
  2074. \
  2075. \*    oFormRef - form object reference (THIS)
  2076. \*    cMenuname - name for menu (this is required for Append menus - see below)
  2077. \*    lRename - renames Name property of your form
  2078. \*    lUniquePopups - determines whether to generate unique ids for popup names
  2079. \            
  2080. \*     example:
  2081. \
  2082. \*    PROCEDURE Init
  2083. \*        DO mymenu.mpr WITH THIS,.T.
  2084. \*    ENDPROC
  2085. \
  2086. \* Use the optional 2nd parameter if you plan on running multiple instances
  2087. \* of your Top-Level form. The preferred method is to create an empty string
  2088. \* variable and pass it by reference so you can receive the form name after
  2089. \* the MPR file is run. You can later use this reference to destroy the menu.
  2090. \
  2091. \*    PROCEDURE Init
  2092. \*        LOCAL cGetMenuName
  2093. \*        cGetMenuName = ""
  2094. \*        DO mymenu.mpr WITH THIS, m.cGetMenuName
  2095. \*    ENDPROC
  2096. \
  2097. \* The logical lRename parameter will change the name property of your 
  2098. \* form to the same name given the menu and may cause conflicts in your 
  2099. \* code if you directly reference the form by name.
  2100. \
  2101. \* You will also need to remove the menu when the form is destroyed so that it does 
  2102. \* not remain in memory unless you wish to reactivate it later in a new form.
  2103. \
  2104. \* If you passed the optional lRename parameter as .T. as in the above example, 
  2105. \* you can easily remove the menu in the form's Destroy event as shown below.
  2106. \* This strategy is ideal when using multiple instances of Top-Level forms.
  2107. \
  2108. \*    example:
  2109. \
  2110. \*    PROCEDURE Destroy
  2111. \*        RELEASE MENU (THIS.Name) EXTENDED
  2112. \*    ENDPROC
  2113. \
  2114. \* Using Append/Before/After location options:
  2115. \
  2116. \*   You might want to append a menu to an existing Top-Level form by setting 
  2117. \*   the Location option in the General Options dialog. In order to do this, you 
  2118. \*   must pass the name of the menu in which to attach the new one. The second
  2119. \*   parameter is required here. If you originally created the menu with the lRename 
  2120. \*   parameter = .T., then you can update the menu with code similar to the following:
  2121. \
  2122. \*    example:
  2123. \
  2124. \*    DO mymenu2.mpr WITH THISFORM,THISFORM.name
  2125. \*
  2126. \* Using lUniquePopups:
  2127. \
  2128. \*   If you are running this menu multiple times in your application, such as in multiple 
  2129. \*   instances of the same top-level form, you should pass .T. to the lUniquePopups 
  2130. \*   parameter so that unique popup names are generated to avoid possible conflicts.
  2131. \
  2132. \*    example:
  2133. \
  2134. \*    PROCEDURE Init
  2135. \*        DO mymenu.mpr WITH THIS,.T.,.T.
  2136. \*    ENDPROC
  2137. \*
  2138. \* Note: Parm4-Parm9 are not reserved and freely available for use with your menu code.
  2139. \*
  2140. \
  2141. \LPARAMETERS oFormRef, getMenuName, lUniquePopups, parm4, parm5, parm6, parm7, parm8, parm9
  2142. \LOCAL cMenuName, nTotPops, a_menupops, cTypeParm2, cSaveFormName
  2143. \IF TYPE("m.oFormRef") # "O" OR ;
  2144. \  LOWER(m.oFormRef.BaseClass) # 'form' OR ;
  2145. \  m.oFormRef.ShowWindow # 2
  2146. \    MESSAGEBOX(<<c_sdierrdisplay_loc>>)
  2147. \    RETURN
  2148. \ENDIF
  2149.  
  2150. \m.cTypeParm2 = TYPE("m.getMenuName")
  2151. \m.cMenuName = SYS(2015)
  2152. \m.cSaveFormName = m.oFormRef.Name
  2153.  
  2154. *!*    \DO CASE
  2155. *!*    \CASE m.cTypeParm2 = "C" AND !EMPTY(m.getMenuName)
  2156. *!*    \    m.cMenuName = m.getMenuName
  2157. *!*    \CASE m.cTypeParm2 = "C" OR (m.cTypeParm2 = "L" AND m.getMenuName)
  2158. *!*    \    m.oFormRef.Name = m.cMenuName
  2159. *!*    \ENDCASE
  2160.  
  2161. \IF m.cTypeParm2 = "C" OR (m.cTypeParm2 = "L" AND m.getMenuName)
  2162. \    m.oFormRef.Name = m.cMenuName
  2163. \ENDIF
  2164. \IF m.cTypeParm2 = "C" AND !EMPTY(m.getMenuName)
  2165. \    m.cMenuName = m.getMenuName
  2166. \ENDIF
  2167.  
  2168. LOCAL ntotpops,cPopRef ,i
  2169. SELECT PADR(LOWER(name),25) FROM (DBF());
  2170.     WHERE numitems#0 AND objtype =2 AND ATC("_MSYSMENU",levelname)=0;
  2171.     INTO ARRAY g_aPops
  2172. m.ntotpops=_TALLY
  2173. IF m.ntotpops>0
  2174.     DIMENSION g_aPops[m.ntotpops]
  2175.     \DIMENSION a_menupops[<<m.ntotpops>>]
  2176.     \IF TYPE("m.lUniquePopups")="L" AND m.lUniquePopups
  2177.     \    FOR nTotPops = 1 TO ALEN(a_menupops)
  2178.     \        a_menupops[m.nTotPops]= SYS(2015)
  2179.     \    ENDFOR
  2180.     \ELSE
  2181.     FOR i = 1 TO ALEN(g_aPops)
  2182.         g_aPops[m.i] = ALLTRIM(g_aPops[m.i])
  2183.         \    a_menupops[<<m.i>>]="<<LOWER(g_aPops[m.i])>>"
  2184.     ENDFOR
  2185.     \ENDIF
  2186.     \
  2187. ENDIF
  2188. ENDFUNC
  2189.  
  2190.  
  2191. * GetMenuType
  2192. * Description: Determines which type of menu we have.
  2193. * Parameters:
  2194. * Return value:
  2195. *
  2196. PROCEDURE GetMenuType
  2197. * Determine if we have a shortcut menu
  2198. LOCATE FOR objtype = c_shortcut
  2199. IF FOUND()
  2200.     m.g_shortcut   = .T.
  2201.     RETURN
  2202. ENDIF
  2203.  
  2204. * Determine if we have SDI menu
  2205. LOCATE FOR objtype = c_sdimenu
  2206. IF FOUND()
  2207.     m.g_inform     = .T.
  2208. ENDIF
  2209. RETURN
  2210.  
  2211. * actpopup
  2212. * Description: writes out code to 
  2213. * activate popup if we have shortcut menu
  2214. * Parameters:
  2215. * Return value:
  2216. *
  2217. PROCEDURE actpopup
  2218. DO CASE
  2219. CASE m.g_shortcut
  2220.     \ACTIVATE POPUP <<m.g_shortcutname>>
  2221. CASE m.g_inform AND m.g_location = c_replace
  2222.     \ACTIVATE MENU (m.cMenuName) NOWAIT
  2223. CASE m.g_inform
  2224.     \ACTIVATE MENU (m.cMenuName) NOWAIT
  2225. ENDCASE
  2226. IF m.g_inform
  2227.     \
  2228.     \IF m.cTypeParm2 = "C"
  2229.     \    m.getMenuName = m.cMenuName
  2230.     \    m.oFormRef.Name = m.cSaveFormName 
  2231.     \ENDIF
  2232.     \
  2233. ENDIF
  2234. RETURN
  2235.  
  2236.  
  2237. ******************************************************************************
  2238. *
  2239. *  File and Path functions
  2240. *
  2241. ******************************************************************************
  2242. *
  2243. * CUTFILELOC - Return a chopped file and path
  2244. *
  2245. *
  2246. FUNCTION cutfileloc
  2247. LPARAMETERS cFile, nLength
  2248. LOCAL cString, cTempPath, cTempFile, nPlen, nFlen
  2249. IF LEN(m.cFile) > m.nLength
  2250.    * Get everything uppercase
  2251.    cFile = UPPER(m.cFile)
  2252.    * Get the filename and length
  2253.    cTempFile = justfname(m.cFile)
  2254.    nFlen = LEN(m.cTempFile)
  2255.    * Find the minimum path length (could be "c:\")
  2256.    cTempPath = cutfpath(STRTRAN(m.cFile,m.cTempFile,"",1),8)
  2257.    nPlen = LEN(m.cTempPath)
  2258.    * If the filename + the min path is longer than nLength, cut the file name.
  2259.    IF m.nFlen + m.nPlen > m.nLength
  2260.       cString = m.cTempPath + cutfname(m.cFile,m.nLength-m.nPlen)
  2261.    ELSE  
  2262.       cTempPath = STRTRAN(m.cFile,m.cTempfile,"",1)
  2263.       cString = cutfpath(m.cTempPath,(m.nLength-m.nFlen)) + m.cTempfile
  2264.    ENDIF
  2265. ELSE
  2266.    cString = m.cFile
  2267. ENDIF   
  2268. RETURN m.cString
  2269.  
  2270.  
  2271.  
  2272. *
  2273. * Function: PARTIALFNAME
  2274. *
  2275. FUNCTION partialfname
  2276. PARAMETER m.filname, m.fillen
  2277. * Return a filname no longer than m.fillen characters.  Take some chars
  2278. * out of the middle if necessary.  No matter what m.fillen is, this function
  2279. * always returns at least the file stem and extension.
  2280. PRIVATE m.bname, m.elipse, m.remain
  2281. m.elipse = "..." + m.g_pathsep
  2282. IF _MAC
  2283.     m.bname = SUBSTR(m.filname, RAT(":",m.filname)+1)
  2284. ELSE
  2285.     m.bname = justfname(m.filname)
  2286. ENDIF
  2287. DO CASE
  2288. CASE LEN(m.filname) <= m.fillen
  2289.    m.retstr = m.filname
  2290. CASE LEN(m.bname) + LEN(m.elipse) >= m.fillen
  2291.    m.retstr = m.bname
  2292. OTHERWISE
  2293.    m.remain = MAX(m.fillen - LEN(m.bname) - LEN(m.elipse), 0)
  2294.    IF _MAC
  2295.        m.retstr = LEFT(SUBSTR(m.filname,1,RAT(":",m.filname)-1),m.remain) ;
  2296.             +m.elipse+m.bname
  2297.    ELSE
  2298.          m.retstr = LEFT(justpath(m.filname),m.remain)+m.elipse+m.bname
  2299.    ENDIF
  2300. ENDCASE
  2301. RETURN m.retstr
  2302.  
  2303.  
  2304.  
  2305. *
  2306. * CUTFNAME - Return a chopped filename
  2307. *  ie: "REALLYLONGFILENAME.TXT" = "REALLYLONG..."
  2308. FUNCTION cutfname
  2309. LPARAMETERS cFilename, nLength
  2310. cFilename = ALLTRIM(m.cFilename)
  2311. IF RAT(m.g_pathsep,m.cFilename) > 0
  2312.    m.cFilename = SUBSTR(m.cFilename,RAT(m.g_pathsep,m.cFilename)+1)
  2313. ENDIF
  2314. IF LEN(m.cFilename) > m.nLength
  2315.    m.cFilename = LEFT(m.cFilename,m.nLength-4) + "..."
  2316. ENDIF
  2317. RETURN m.cFilename
  2318.  
  2319.  
  2320.  
  2321. *
  2322. * CUTFPATH - Return a chopped filepath
  2323. *
  2324. *  ie: "C:\REALLYLONGPATH\SUB\ETC\" = "C:\ ...\SUB\ETC\"
  2325. FUNCTION cutfpath
  2326. LPARAMETERS cFilepath, nLength
  2327. LOCAL cPre, cString, nRemain, nOccurs
  2328. IF _MAC OR LEN(m.cFilepath) > m.nLength
  2329.    cFilePath = SYS(2027, m.cFilePath)  && Remove relative paths
  2330. ENDIF   
  2331. IF LEN(m.cFilepath) > m.nLength
  2332.    cPre = LEFT(m.cFilePath,AT(m.g_pathsep,m.cFilePath)) + "... " + m.g_pathsep
  2333.    nRemain = nLength - LEN(m.cPre)
  2334.    cString = RIGHT(cFilepath,m.nRemain)
  2335.    IF OCCURS(m.g_pathsep,m.cString)>1
  2336.       cString = m.cPre + SUBS(cString,AT(m.g_pathsep,m.cString))
  2337.    ELSE
  2338.       cString = m.cPre  && last directory on path is too long
  2339.    ENDIF
  2340. ELSE
  2341.    cString = m.cFilepath
  2342. ENDIF   
  2343. RETURN m.cString
  2344.  
  2345.  
  2346.  
  2347. *
  2348. * JUSTFNAME - Return just a filename
  2349. *
  2350. FUNCTION justfname
  2351. PARAMETERS m.filname
  2352. PRIVATE ALL
  2353. IF RAT('\',m.filname) > 0
  2354.    m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
  2355. ENDIF
  2356. IF AT(':',m.filname) > 0
  2357.    m.filname = SUBSTR(m.filname,AT(':',m.filname)+1,255)
  2358. ENDIF
  2359. RETURN ALLTRIM(UPPER(m.filname))
  2360.  
  2361.  
  2362. *
  2363. * JUSTPATH - Return just the path name from "filname"
  2364. *
  2365. FUNCTION justpath
  2366. PARAMETERS m.filname
  2367. PRIVATE ALL
  2368. m.filname = ALLTRIM(UPPER(m.filname))
  2369. IF '\' $ m.filname
  2370.    m.filname = SUBSTR(m.filname,1,RAT('\',m.filname))
  2371.    IF RIGHT(m.filname,1) = '\' AND LEN(m.filname) > 1 ;
  2372.          AND SUBSTR(m.filname,LEN(m.filname)-1,1) <> ':'
  2373.       filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
  2374.    ENDIF
  2375.    RETURN m.filname
  2376. ELSE
  2377.    RETURN ''
  2378. ENDIF
  2379.  
  2380.  
  2381. *
  2382. * STRIPEXT - Strip the extension from a file name.
  2383. *
  2384. * Description:
  2385. * Use the algorithm employed by FoxPRO itself to strip a
  2386. * file of an extension (if any): Find the rightmost dot in
  2387. * the filename.  If this dot occurs to the right of a "\"
  2388. * or ":", then treat everything from the dot rightward
  2389. * as an extension.  Of course, if we found no dot,
  2390. * we just hand back the filename unchanged.
  2391. *
  2392. * Parameters:
  2393. * filename - character string representing a file name
  2394. *
  2395. * Return value:
  2396. * The string "filename" with any extension removed
  2397. *
  2398. FUNCTION stripext
  2399. PARAMETER m.filename
  2400. PRIVATE m.dotpos, m.terminator
  2401. m.dotpos = RAT(".", m.filename)
  2402. m.terminator = MAX(RAT("\", m.filename), RAT(":", m.filename))
  2403. IF m.dotpos > m.terminator
  2404.    m.filename = LEFT(m.filename, m.dotpos-1)
  2405. ENDIF
  2406. RETURN m.filename
  2407.  
  2408.  
  2409. *
  2410. * STRIPPATH - Strip the path from a file name.
  2411. *
  2412. * Description:
  2413. * Find positions of backslash in the name of the file.  If there is one
  2414. * take everything to the right of its position and make it the new file
  2415. * name.  If there is no slash look for colon.  Again if found, take
  2416. * everything to the right of it as the new name.  If neither slash
  2417. * nor colon are found then return the name unchanged.
  2418. *
  2419. * Parameters:
  2420. * filename - character string representing a file name
  2421. *
  2422. * Return value:
  2423. * The string "filename" with any path removed
  2424. *
  2425. FUNCTION strippath
  2426. PARAMETER m.filename
  2427. PRIVATE m.slashpos, m.namelen, m.colonpos
  2428. m.slashpos = RAT("\", m.filename)
  2429. IF m.slashpos > 0
  2430.    m.namelen  = LEN(m.filename) - m.slashpos
  2431.    m.filename = RIGHT(m.filename, m.namelen)
  2432. ELSE
  2433.    m.colonpos = RAT(":", m.filename)
  2434.    IF m.colonpos > 0
  2435.       m.namelen  = LEN(m.filename) - m.colonpos
  2436.       m.filename = RIGHT(m.filename, m.namelen)
  2437.    ENDIF
  2438. ENDIF
  2439. RETURN m.filename
  2440.  
  2441.  
  2442. * BASENAME - returns strippath(stripext(filespec))
  2443. *
  2444. FUNCTION basename
  2445. PARAMETER m.filespec
  2446. RETURN strippath(stripext(m.filespec))
  2447.  
  2448.  
  2449.  
  2450. ******************************************************************************
  2451. * Revisions History
  2452. * $History: GENMENU.PRG $
  2453.  * 
  2454.  * *****************  Version 11  *****************
  2455.  * User: rb          Date: 11/30/96    Time: 1:04a
  2456.  * Updated in $/Genmenu
  2457.  * Enhanced #PREPOP for Cleanup snippet placeholder
  2458.  * Changed naming convention of menu popups in Top-Level
  2459.  *    form menus to avoid conflicts with RELEASE MENU...
  2460.  *    extended.
  2461.  * Fixed Top-Level Form - append menu problem.
  2462.  * Fixed Setup/Cleanup code not gen for Top-Level Form.
  2463.  * *****************  Version 10  *****************
  2464.  * User: rb          Date: 5/1/96    Time: 1:04a
  2465.  * Updated in $/Genmenu
  2466.  * Added #PREPOPUP generator directive to control whether
  2467.  * Cleanup code is placed before/after ACTIVATE POPUP
  2468.  * line for Shortcut menus. 
  2469.  * *****************  Version 9  *****************
  2470.  * User: rb          Date: 3/8/96    Time: 1:04a
  2471.  * Updated in $/Genmenu
  2472.  * Added support for new shortcut popup and SDI form menus
  2473.  * - actpopup() new proc to add shortcut activate code
  2474.  * - GetMenuType() new proc to determine menu type (shortcut, SDI, etc.)
  2475.  * - defbars () added new parameter to safeguard shortcut popup name
  2476.  * - defonbar () added new parameter to safeguard shortcut popup name
  2477.  * *****************  Version 8  *****************
  2478.  * User: Dta          Date: 3/19/95    Time: 1:04a
  2479.  * Updated in $/Genmenu
  2480.  * - Thermfname() modified to use new function CutFileLoc().
  2481.  * - CutFileLoc(), CutFPath() and CutFName() written to handle 
  2482.  *   formating for long file, path and directory names.
  2483.  * - Grouped similiar functions.
  2484.  * - Fixed release thermometer window bug.
  2485.  * - Merge dialog and thermometer fonts.
  2486.  * - Moved g_pathsep to globals definition area.
  2487.  * 
  2488.  * *****************  Version 7  *****************
  2489.  * User: Dta          Date: 3/18/95    Time: 7:36p
  2490.  * Updated in $/Genmenu
  2491.  * - Change c_aliaslen to 255 to support long file names.
  2492.  * - Add support for intelligent Pad hotkeys
  2493.  * 
  2494.  * *****************  Version 6  *****************
  2495.  * User: Dta          Date: 3/18/95    Time: 5:19p
  2496.  * Updated in $/Genmenu
  2497.  * - Add support for no "!" in menu file name.
  2498.  * - Modify error routine to utilize MESSAGEBOX()
  2499.  * 
  2500.  * *****************  Version 5  *****************
  2501.  * User: Dta          Date: 1/11/95    Time: 9:45a
  2502.  * Updated in $/Genmenu
  2503.  * - Beautified and documentation changes
  2504.  * - Branched for Localization
  2505.  *
  2506.  * *****************  Version 4  *****************
  2507.  * User: Dta          Date: 1/10/95    Time: 6:36p
  2508.  * Updated in $/Genmenu
  2509.  * - Add support for DEBUG mode
  2510.  * - Add message for ERROR 22
  2511.  * - #DEFINEs moved above executable code
  2512.  * - Dialog Fonts changed for localization
  2513.  *
  2514.  * *****************  Version 3  *****************
  2515.  * User: Dta          Date: 1/10/95    Time: 5:56p
  2516.  * Updated in $/Genmenu
  2517.  * - Change localization constants to support naming convention.
  2518.  *
  2519.  * *****************  Version 2  *****************
  2520.  * User: Dta          Date: 12/10/94    Time: 8:20a
  2521.  * Updated in $/Genmenu
  2522.  * - Change PJXFields constant to 3.0 value.
  2523.  * - Add AGAIN to USE command when opening project.
  2524.  * - Add constants for Localization support.
  2525.  * - Remove "arranged" from NOCPTRANS command.
  2526.  * - Modify VERSNUM() to support 3.0 VERS() convention.
  2527.  * - Add version control documentation.
  2528.  *
  2529.  * *****************  Version 1  *****************
  2530.  * User: Dta          Date: 12/1/95    Time: 3:13p
  2531.  * Added in $/Genmenu
  2532.  * - Orignial 2.6a GENMENU shipping version.
  2533.  *
  2534. *
  2535.  
  2536.